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

为什么TypeScript不允许泛型中存在循环类型引用?

TypeScript 自引用类型泛型封装失效说明

如下是类型在定义中直接引用自身的示例,但该用法经过泛型抽象后会完全失效:

type a = { val: a }; // <-- 不限制循环引用!

type record<T> = { val: T };

type b = record<b>; // <-- 无法正常工作!

type func<T> = (arg: T) => void;

type c = func<c>; // <-- 无法正常工作!

type d = (arg: d) => void; // <-- 可以正常生效!?

原因说明

  • TypeScript原生支持对象、函数类型在定义时直接递归引用自身,因此type a、type d的写法可以正常通过校验,不会判定为非法循环。
  • 泛型实例化的校验逻辑和直接定义类型不同:当尝试为泛型传入还在定义过程中的自身类型作为参数时,TS的循环检测机制会优先判定该写法存在非法循环引用,不会先展开泛型结构再校验,因此type b和type c会报错。
  • 函数类型的直接自引用是TS做了特殊兼容的场景,该兼容逻辑仅对直接定义的函数类型生效,封装为泛型后不会触发。

解决方案

如果需要实现泛型化的递归类型,可以通过显式将递归逻辑写到泛型内部绕开校验,示例如下:

// 递归对象泛型的正确写法
type RecursiveRecord<T> = {
  val: RecursiveRecord<T>
} & T
// 等价于直接定义的type a,还支持额外扩展属性
type b = RecursiveRecord<{}>

// 递归函数泛型的正确写法
type RecursiveFunc<T> = (arg: RecursiveFunc<T>) => T
// 等价于直接定义的type d
type c = RecursiveFunc<void>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 06:24:08