关于TypeScript结构类型系统的疑问及代码示例解析
关于TypeScript结构类型系统的疑问及代码示例解析
嘿,我来帮你拆解这个TypeScript的小困惑!先看你给出的这段代码示例:
type Foo1<K extends string, V> = { [key in K]: V } type Foo2<K extends string, V> = { [key in K]: V } function values1<T>(foo: Foo1<string, T>) { return Object.values(foo) } function values2<T>(foo: Foo2<string, T>) { return Object.values(foo) } function test<K extends string>(foo: Foo1<K, string>) { const v1 = values1(foo) // string[] const v2 = values2(foo) // unknown[] }
是不是很奇怪?明明Foo1和Foo2的定义完全一模一样,为什么把同一个foo传给values1和values2,返回值类型会差这么多?我来给你捋清楚:
- 首先,TypeScript是结构类型系统,理论上结构完全相同的类型应该是兼容的,但这里的关键在于泛型类型的身份匹配。
- 当你把
foo(类型是Foo1<K, string>)传给values1时,values1的参数是Foo1<string, T>——这俩都是Foo1这个泛型的不同实例。TypeScript能顺着同一个泛型的结构关联,推断出T应该是string(因为foo里所有属性的值都是string类型),所以values1(foo)的返回值就是string[]。 - 而传给
values2的时候,情况就不一样了:values2的参数是Foo2<string, T>,虽然Foo2和Foo1结构完全相同,但它们是TypeScript里两个独立定义的泛型类型。这时候TypeScript没办法直接把Foo1<K, string>和Foo2<string, T>的泛型参数做精准匹配,没办法确定T的具体类型,只能 fallback 到最宽泛的unknown,所以values2(foo)的返回值就成了unknown[]。
简单说就是:同名泛型的不同实例之间,TypeScript的类型推断会更“聪明”;而两个结构相同但名字不同的泛型,在跨类型推断时会更保守,容易出现类型丢失的情况。
备注:内容来源于stack exchange,提问作者riv
相关产品推荐
相关产品推荐

