关于 TS 类型别名的使用大部分同学可能只知道联合类型玩法,其实它还能做递归的类型声明和继承
基本使用
还是从基础开始,看一下类型别名的基本使用,再一点点向下深入
类型别名声明能够定义一个类型别名,它的基本语法如下所示:
type AliasName = Type // 语法
类型别名引用的类型可以为任意类型,例如原始类型、对象类型、联合类型和交叉类型等。示例如下:
type StringType = string;
type BooleanType = true | false
type Point = { x: number; y: number; z?: number };
也可以引用其他类型别名,示例如下:
type Numberic = number | bigint;
type StringOrNumber = string | Numberic; // string | number | bigint
类型别名不会创建出一种新的类型,它只是给已有类型命名并直接引用该类型,所以我们完全可以使用‘值’去替换掉类型别名。我们使用类型别名往往是为了更好的标示类型特征或者是复用,示例如下:
type StringOrNumber = string | number
const value1: StringOrNumber = 123 // 更好的标示数据类型特征
const value2: string | number = 123 // 完全可以用值替换,不用类型别名
type DecimalDigit = 0 | 1 | 2 | 3 | 4 // 遇到这种联合类型,利用类型别名完成复用,它不香么?
const digit1: DecimalDigit = 1;
const digit2: DecimalDigit = 2;
递归的类型别名
看完上面的基础知识,我想你知道对类型别名有了一定的认知,那么下面开始对它的递归使用进行学习,要耐心噢!
一般情况下,在类型别名声明中赋值运算符右侧的类型不允许引用当前定义的类型别名。因为类型别名对其引用的类型使用的是及早求值的策略,而不是惰性求值的策略。因此,如果类型别名引用了自身,那么在解析类型别名时就会出现无限递归引用的问题。示例如下:
type T = T // 哒咩~ 编译错误,存在循环引用
在TypeScript 3.7版本中,编译器对类型别名的解析进行了一些优化。在类型别名所引用的类型中,使用惰性求值的策略来解析泛型类型参数。因此,允许在泛型类型参数中递归地使用类型别名。通过递归的类型别名能够定义一些特别常用的类型。TypeScript官方文档中给出了使用递归的类型别名来定义Json类型的例子。示例如下:
type Json =
| string
| boolean
| number
| null
| { [property: string]: Json }
| Json[];
const data: Json = [
{
name: {
first: 'zhang',
last: 'dan'
}
}
]
类型别名与接口继承对比
接口可以继承其他的接口、类等对象类型,而类型别名则不支持继承。
若要对类型别名实现类似继承的功能,则需要使用一些变通方法。例如,当类型别名表示对象类型时,可以借助于交叉类型来实现继承的效果。示例如下:
type Shape = { name: string };
type Circle = Shape & { radius: number }
function foo(circle: Circle) {
const name = circle.name;
const radius = circle.radius;
}
总结
总之,牢牢记住类型别名的场景(特殊标示,复用)比起记它的使用细节要重要得多!看完记得点赞,收藏,关注哈!
《TypeScript 入门与实战》钟胜平