TypeScript类型层面为何部分场景需NoInfer,部分场景却不需要?
TypeScript中IsAny约束的循环引用问题与NoInfer的作用解析
IsAny类型工具的标准定义
IsAny是判断类型是否为any的常用类型工具,标准实现如下:
type IsAny<T> = 0 extends 1 & T ? true : false;
未使用NoInfer时的循环引用错误
将IsAny用作类型参数的约束条件时,会触发循环引用错误:
type TShouldNotBeAny<T extends IsAny<T> extends true ? never : unknown> = T; // 错误提示:Type parameter 'T' has a circular constraint.
添加NoInfer修复错误
在IsAny的定义中引入NoInfer<T>后,循环引用错误被修复,且约束逻辑正常生效:
type IsAny<T> = 0 extends 1 & NoInfer<T> ? true : false; type TShouldNotBeAny<T extends IsAny<T> extends true ? never : unknown> = T; // 无错误 type T1 = TShouldNotBeAny<string>; // 允许通过 type T2 = TShouldNotBeAny<number>; // 允许通过 type T3 = TShouldNotBeAny<any>; // 符合预期:不允许通过,提示Type 'any' does not satisfy the constraint 'never'.
IsString场景无需NoInfer的对比
类似的IsString约束场景却不需要使用NoInfer,也不会出现循环引用错误:
type IsString<T> = T extends string ? true : false; type TShouldNotBeString<T extends IsString<T> extends true ? never : unknown> = T; // 无错误 type T1 = TShouldNotBeString<number>; // 允许通过 type T2 = TShouldNotBeString<bigint>; // 允许通过 type T3 = TShouldNotBeString<string>; // 符合预期:不允许通过,提示Type 'string' does not satisfy the constraint 'never'.
疑问与分析
按常理推断:
- IsAny场景中,T并非类型推断点,理论上NoInfer不应起作用
IsAny<T> extends true的逻辑应该能直接根据T的类型返回true/false,不会构成循环引用——只有当约束条件中出现T extends T这类逻辑时,才会触发循环引用,比如下面的例子:
type TShouldNotBeAny<T extends IsAny<T> extends true ? never : T> = T; // 依然报错 // 注意:这里用T代替了unknown
上述代码即便添加NoInfer也会报错,这符合预期。但为什么NoInfer在最初的IsAny约束场景中却能解决循环引用问题?
内容的提问来源于stack exchange,提问作者Developer
相关产品推荐
相关产品推荐

