关于TypeScript中<T extends any[]>泛型约束的使用疑问
理解偏差说明
- 你对
T extends any[]的基础认知是对的:该约束确实表示T至少包含数组的全部属性,可以被当作数组使用。问题出在你flattenArray的返回值要求和泛型T完全匹配,但你实际的返回值满足不了这个要求。 - 第一个报错
Type 'T[number][]' is not assignable to type 'T'的原因:[...prev, ...curr]展开两个T类型的数组后,得到的是仅包含T元素的普通数组,类型为T[number][]。但T可以是数组的子类型,比如以下带自定义属性的数组类型:
// 这是合法的数组子类型,既符合数组结构,又有额外的tag属性 type CustomArray = string[] & { tag: string }
展开两个CustomArray类型的数组,得到的只是普通string[],没有tag属性,自然无法赋值给T类型,因此触发报错。
- 第二个报错
Conversion of type 'never[]' to type 'T' may be a mistake的原因:空数组[]的默认类型是never[],同样无法满足T可能存在的额外属性约束,强制类型转换自然会被TS提示风险。 - 对比
getLength为什么无报错:因为getLength的返回值是固定的number类型,只用到了数组共有的length属性,不需要返回和T完全匹配的类型,自然不会触发类型冲突。
T extends any[]的正确使用逻辑
- 当你的逻辑只需要消费数组的通用属性/方法,不需要返回和泛型T完全一致的类型时,可以放心用该约束,比如需要接收带自定义属性的数组做参数、只读取数组属性的场景。
- 如果你的逻辑需要返回和泛型T完全匹配的类型,你必须保证返回值能覆盖T的所有约束(包括可能存在的额外属性),否则不要用该约束。
- 针对你的
flattenArray场景,如果你不需要支持带额外属性的数组入参,最开始的普通泛型写法function flattenArray<T>(a:T[][]): T[]就是最优解,完全不需要用T extends any[]的写法做多余的约束。
内容的提问来源于stack exchange,提问作者Mrk Sef
相关产品推荐
相关产品推荐

