TypeScript 如何做递归类型

很多朋友刚接触 TypeScript 时,会发现它比 JavaScript 多了很多“约束规则”,这些规则看似麻烦,却能帮我们提前揪出代码里的小错误——就像给代码加了一本“字典”,告诉编译器什么样的数据是合法的。而递归类型,就是这本字典里能“举一反三”的特殊规则,今天咱们就用生活化的例子把它说透。

什么是递归类型?

先想个日常场景:你整理衣柜,里面叠着衣服,最外层是一件外套,掀开外套里是一件毛衣,毛衣里面藏着一件短袖,这就是“套娃”一样的层级结构。递归类型就是用来定义这种“自己套自己”的结构的。

TypeScript 如何做递归类型

用 JavaScript 写这种结构很简单,比如一个无限嵌套的对象:

`javascript

const nestedData = {

value: 10,

next: {

value: 20,

next: {

value: 30,

next: null

}

}

};

`

但如果用 JavaScript 写函数处理它,很容易把属性写错,比如把value写成val,编译器根本不会提醒。这时候 TypeScript 的递归类型就能派上用场——它能自动识别这种嵌套结构的每一层,保证每一层的属性都符合规则。

怎么用 TypeScript 写递归类型?

写递归类型的核心,就是在类型定义里“引用自己”,就像套娃里的“娃娃”本身还是“套娃”。咱们还是用刚才的嵌套对象举例:

`typescript

// 定义一个递归类型

type NestedNumber = {

value: number;

// 这里引用自己,next可以是NestedNumber或者null(到最底层就断了)

next: NestedNumber | null;

};

// 用这个类型定义变量,编译器就会自动检查每一层

const validData: NestedNumber = {

value: 10,

next: {

value: 20,

next: {

value: 30,

next: null

}

}

};

`

这时候如果把next里的value改成字符串,比如value: "20",TypeScript 会立刻报错:“这里应该是数字,你给了字符串”,比 JavaScript 安全多了。

递归类型的两种常见用法

递归类型不是只能用来套对象,还有两种特别实用的场景,咱们用例子说清楚。

第一种是处理数组的嵌套结构。比如你做一个多层级的商品分类:家电下面分电视、冰箱,电视下面又分OLED、LED,这时候可以用递归类型定义:

`typescript

// 分类的每一项,要么是字符串,要么是包含子分类的结构

type Category = string | { name: string; children: Category[] };

const phoneCategory: Category = {

name: "数码",

children: [

{

name: "手机",

children: ["苹果", "华为"]

},

"平板"

]

};

`

这个类型能保证children里不管是子分类还是字符串,都符合规范,不会出现格式混乱。

第二种是处理函数的嵌套。比如你要做一个能无限嵌套的计算函数,比如add(1)(2)(3),这时候递归类型可以这样写:

`typescript

type AddFunc = (num: number) => AddResult;

type AddResult = AddFunc | number;

// 实现这个函数

const add = (x: number): AddFunc => (y) => add(x + y);

// 最后取结果时加个valueOf就行,或者自己包装一下

console.log(add(1)(2)(3).valueOf()); // 输出6

`

这里的AddFunc引用了自己,保证每次调用返回的都是符合要求的函数,不会变成别的类型。

写递归类型要注意的小坑

递归类型虽然好用,但有个关键细节不能忘:必须有“终止条件”,也就是刚才例子里的next: null或者number,不然会变成无限循环,编译器会报错。比如如果刚才的NestedNumber里没有null,就会一直套自己,永远定义不完。

另外,递归类型不能随便乱用。如果你的数据最多只有1层嵌套,完全没必要写递归类型,直接写{ value: number; next: number }就行,不然会让类型变得复杂,反而增加代码的理解成本。

总的来说,TypeScript的递归类型就是给“套娃数据”做了一本精准的说明书,让编译器帮你盯着每一层的格式,不用等到运行时才发现错误。掌握了这个技巧,你就能轻松应对那些多层嵌套的复杂数据结构了。

上一篇 PHP composer 如何更新依赖