条件类型不健全性:何时X=>string会与any=>string被统一?
TypeScript条件类型不健全性示例解析
先明确核心问题:TypeScript的条件类型统一算法在处理逆变位置的类型参数时,会错误地将泛型参数X拓宽为any,导致(x: X) => string与(x: any) => string被判定为兼容,进而引发运行时错误。
逆变位置的基本规则
函数的参数类型属于逆变位置:若A extends B,则(x: B) => void extends (x: A) => void。简单说,接受更宽泛参数的函数可以替代接受更窄参数的函数,反之则不行。比如(x: any) => string可以赋值给(x: number) => string(因为any能包含number),但(x: number) => string绝对不能赋值给(x: any) => string(传入非number会报错)。
错误统一的示例
1. 条件类型判断错误
type IsCompatible<X> = ((x: X) => string) extends ((x: any) => string) ? true : false; // 预期:IsCompatible<number>应为false(因为number函数不能接受any参数) // 实际:TypeScript返回true,算法错误将X拓宽为any type TestNumber = IsCompatible<number>; // true type TestString = IsCompatible<string>; // true
这里TypeScript错误认为任意(x: X) => string都兼容(x: any) => string,完全违背了逆变规则。
2. 运行时错误场景
基于上面的错误判断,TypeScript会允许不安全的函数赋值,最终导致运行时崩溃:
function unsafeAssign<X>(fn: (x: X) => string): (x: any) => string { return fn; // TypeScript认为这个赋值合法,但实际不安全 } // 定义一个仅接受number的函数 const numToFixed = (x: number) => x.toFixed(2); // 错误地获得一个声称接受any的函数 const anyToFixed = unsafeAssign(numToFixed); // 运行时错误:传入字符串调用,x.toFixed不存在 anyToFixed("hello"); // Uncaught TypeError: x.toFixed is not a function
为什么你的测试代码表现正常
你测试的type Test<X> = ((x:X) => string) extends ((x:number) => string) ? true : false符合逆变规则:
- 当
X extends number时,(x: number) => stringextends(x: X) => string,所以Test<X>返回true(比如Test<number>为true); - 当X是其他类型(如string),
(x:string) => string不extends(x:number) => string,返回false。
这个场景中没有涉及any的错误拓宽,所以结果符合预期。
内容的提问来源于stack exchange,提问作者Andrea Simone Costa
相关产品推荐
相关产品推荐

