TypeScript函数向联合类型数组推入错误类型为何无编译错误?
为什么这段TypeScript代码能无错误编译,以及如何检测这类类型不安全问题
这段代码能编译通过,核心原因是TypeScript在默认编译模式下,对数组类型采用了协变的类型兼容性规则:
string是StrNum(string | number)的子类型,所有string类型的值都符合StrNum的约束;- 默认模式下,若类型
A是B的子类型,那么A[]会被视为B[]的子类型,所以string[]可以赋值给StrNum[]类型的参数。
但这里存在明显的类型安全隐患:StrNum[]的push方法允许传入number类型值,而你传入的strArr本质是string[]数组。调用arr.push(1)后,原本只能存储字符串的数组被插入了数字,导致运行时数组的实际类型与声明的string[]不符。
如何检测并避免这类问题
开启
--strictFunctionTypes编译选项
这个选项会启用更严格的函数参数类型检查。在该模式下,数组的类型兼容性会遵循函数参数的逆变规则:StrNum[]的push方法接受string | number,而string[]的push仅接受string,此时string[]无法赋值给StrNum[],编译器会直接报错,阻止不安全的赋值操作。使用只读数组约束参数
如果函数不需要修改数组,可将参数类型改为readonly StrNum[],此时push方法会直接报错(只读数组不支持修改操作),从根源避免类型污染:type StrNum = string | number; const strArr: string[] = []; function addToArray(arr: readonly StrNum[]): void { // arr.push(1); // 报错:Property 'push' does not exist on type 'readonly StrNum[]' } addToArray(strArr);避免使用宽松的数组类型参数
尽量不要用联合类型数组作为允许修改的参数类型,或者在需要修改时,确保传入的数组本身就兼容联合类型(比如直接声明StrNum[]类型的数组)。
内容的提问来源于stack exchange,提问作者jerichaux
相关产品推荐
相关产品推荐

