You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript无递归条件映射类型NoOp等效原类型的原理探究

TypeScript 递归泛型NoOp的底层机制解析

先看示例代码:

// 等效于T
type NoOp<T> = {
  [P in keyof T]: NoOp<T[P]>;
};

// 使用示例:
type ObjType = { a: string, b: { c: number, d: boolean} };
type NoOpObj = NoOp<ObjType>; // 等效于ObjType
type NoOpString = NoOp<string>; // string

一、为什么看似无条件递归却不报错?

核心原因是TypeScript的类型惰性求值和循环引用自动终止机制:

  • TypeScript的类型系统是按需解析的,只有当类型被实际用于类型断言、变量声明、函数参数/返回值标注等场景时,才会触发类型展开。如果只是定义类型而不使用,递归逻辑根本不会执行。
  • 当类型被触发解析时,TypeScript会自动检测递归过程中的循环引用。比如处理NoOp<ObjType>时,递归到NoOp<string>、NoOp<number>这类原始类型后,继续递归的结果不会产生新的类型(原始类型的属性方法递归后最终还是回到原始类型或内置固定类型),此时TypeScript会直接终止递归,避免无限循环报错。

二、为什么NoOp等于string本身?

这涉及TypeScript的类型等价规则和原始类型的特殊处理:

  • 虽然keyof string能拿到concat、slice等原型方法,但当对原始类型使用映射类型{[P in keyof T]: ...}时,TypeScript会将生成的“对象包装类型”和原始类型视为完全等价。比如{[P in keyof string]: string[P]}和string在类型检查中没有任何区别。
  • 当递归到原始类型时,TypeScript会直接短路递归返回原类型。因为继续递归原始类型的属性(比如NoOp<typeof string.prototype.concat>),最终得到的类型不会改变原始类型的本质,递归失去意义,因此TypeScript会直接终止递归,让NoOp<string>等于string。

内容的提问来源于stack exchange,提问作者aldel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 08:09:53