2017-08-25 71 views
1

因此,我发现在打字稿中有一个技巧,通过将类型映射到键值对,然后使用keyof类型创建可以是地图中的任何值的类型,将对象类型转换为区分的联合。下面是一个简单的例子:泛型中[typof T]的原因与硬编码类型有不同的语义?

type SourceType = 
{ 
    foo: number, 
    bar: string 
}; 
type MapWithKey<T> = {[P in keyof T]: { key: P, value: T[P] }} 
type DescriminatedUnion = MapWithKey<SourceType>[keyof SourceType]; 
//The DescriminatedUnion now has the following type 
DescriminatedUnion ≡ {key:"foo",value:string} | {key:"bar",value:number} 

,如果你想,当你试图使这个结构完全通用的,你最终有一个不同类型但指定一个非常大的可识别联合,这是非常有用的。

type MakeDescriminatedUnion<T> = MapWithKey<T>[keyof T]; 
type DescriminatedUnion = MakeDescriminatedUnion<SourceType> 
//The DescriminatedUnion now has the followin type 
DescriminatedUnion ≡ {key:"foo"|"bar",value:number|string} 

这应该是相同的类型,但由于某种原因它不是。我试图通过打字稿找到一些推理,但我不能。有谁知道这种差异的原因吗?或者甚至更好,有人知道一种方法来解决这种行为,并使其完全通用?

+3

[此问题](https://stackoverflow.com/questions/43898999/creating-a-discriminated-union-using-the-property-names-of-another-type)看起来非常相似,这里是[github问题](https://github.com/Microsoft/TypeScript/issues/15756)和[这里是修复](https://github.com/Microsoft/TypeScript/pull/18042) – artem

+0

谢谢!这比我预想的要多得多。 @artem –

回答

1

是的,this issue已经咬了mequite几个others。令人惊讶的是,正如@artem提到的那样,a fix将在今天推出!

同时,对于我们这些被困在打字稿2.4的土地,有使用default generic type parameters解决方法:

type MakeDiscriminatedUnion<T, M extends MapWithKey<T> = MapWithKey<T>> = M[keyof T]; 
type DiscriminatedUnion = MakeDiscriminatedUnion<SourceType> // okay now 

M的实际价值没有得到评估,直到您使用MakeDiscriminatedUnion<SourceType>,所以编译器没有机会像上面那样“简化”M[keyof T]

无论如何,无论是使用解决方法还是等待TypeScript 2.6,都是您的选择。希望有所帮助。祝你好运!

+0

感谢您的解决!无法在其他地方找到它完美无缺的工作! –