这是我参与更文挑战的第十三天,活动详情查看:更文挑战
TS 的高级类型是,TS 为了保证语言的灵活性,所引用的一些语言特性。这些特性有利于应对复杂多变的开发场景
什么是交叉类型
将多个类型合并为一个类型,新的类型将具有所有类型的特性,所以交叉类型特别适合对象过多的场景。交叉类型实际上是取所有类型的并集
interface DogInterface {
run(): void;
}
interface CatInterface {
jump(): void;
}
// pet变量将具有两个接口类型的所有方法
/*
不能将类型“{}”分配给类型“DogInterface & CatInterface”。
类型 "{}" 中缺少属性 "run",但类型 "DogInterface" 中需要该属性。ts(2322)
*/
let pet: DogInterface & CatInterface = {};
复制代码
interface DogInterface {
run(): void;
}
interface CatInterface {
jump(): void;
}
// pet变量将具有两个接口类型的所有方法
let pet: DogInterface & CatInterface = {
run() {},
jump() {},
};
复制代码
什么是联合类型
声明的类型并不确定,可以为多个类型中的一个
let a: number | string = "a";
let b: number | string = 1;
复制代码
有时候不仅要限制变量的类型,还需要限定变量的取值在某个特定的范围内
字符串的字面量联合类型
// testName是一个联合类型,并且取值必须是 'a'|'b'|'c' 中的一个
let testName: "a" | "b" | "c";
复制代码
数字的字面量联合类型
let testName: 1 | 2 | 3;
复制代码
对象的联合类型
如果对象时联合类型,在对象不确定的情况下,只能访问所有类型的公有有成员( 这种情况下的联合类型只能取所有成员的交集)
interface DogInterface {
run(): void;
}
interface CatInterface {
jump(): void;
}
// pet变量将具有两个接口类型的所有方法
let pet: DogInterface & CatInterface = {
run() {},
jump() {},
};
class Dog implements DogInterface {
run() {}
eat() {}
}
class Cat implements CatInterface {
jump() {}
eat() {}
}
enum Master {
Boy,
Girl,
}
function getPet(master: Master) {
// 类型推断为: (let pet: Dog | Cat) 联合类型
let pet = master === Master.Boy ? new Dog() : new Cat();
// 编译器提示只能调用 eat 方法
pet.eat();
return pet;
}
复制代码
可区分的联合类型
本质上是结合联合类型与字面量类型的一种类型保护方法。核心思想:一个类型如果是多个对象的联合类型,并且每个类型之间有一个公共属性,就可以凭借此公共属性,创建类型保护区块
interface Square {
kind: "square";
size: number;
}
interface Reactangle {
kind: "reactangle";
width: number;
height: number;
}
type Shape = Square | Reactangle;
function area(s: Shape) {
// 通过两个类型的共有属性 kind,就可以创建类型保护区块
switch (s.kind) {
case "reactangle":
return s.height * s.width;
case "square":
return s.size * s.size;
}
}
复制代码
上面的代码如果不升级维护是没有问题的,但是如果添加了一个新的形状后呢?
interface Square {
kind: "square";
size: number;
}
interface Reactangle {
kind: "reactangle";
width: number;
height: number;
}
interface Circle {
kind: "circle";
r: number;
}
type Shape = Square | Reactangle | Circle;
function area(s: Shape) {
switch (s.kind) {
case "reactangle":
return s.height * s.width;
case "square":
return s.size * s.size;
}
}
// 打印出undefined
console.log(area({ kind: "circle", r: 100 }));
复制代码
解决方式一:为函数指定一个明确的返回类型
interface Square {
kind: "square";
size: number;
}
interface Reactangle {
kind: "reactangle";
width: number;
height: number;
}
interface Circle {
kind: "circle";
r: number;
}
type Shape = Square | Reactangle | Circle;
/*
函数缺少结束 return 语句,返回类型不包括 "undefined"。ts(2366)
*/
function area(s: Shape): number {
switch (s.kind) {
case "reactangle":
return s.height * s.width;
case "square":
return s.size * s.size;
}
}
console.log(area({ kind: "circle", r: 100 }));
复制代码
解决方式二: 检查是否是 never
类型,如果是 never
类型,说明前面所有的分支都被覆盖了, 如实 s
不是 never
类型,就说明前面的分支有遗漏
interface Reactangle {
kind: "reactangle";
width: number;
height: number;
}
interface Circle {
kind: "circle";
r: number;
}
type Shape = Square | Reactangle | Circle;
function area(s: Shape) {
switch (s.kind) {
case "reactangle":
return s.height * s.width;
case "square":
return s.size * s.size;
default:
/*
类型“Circle”的参数不能赋给类型“never”的参数。ts(2345)
*/
return ((e: never) => {
throw new Error(e);
})(s);
}
}
console.log(area({ kind: "circle", r: 100 }));
复制代码
interface Square {
kind: "square";
size: number;
}
interface Reactangle {
kind: "reactangle";
width: number;
height: number;
}
interface Circle {
kind: "circle";
r: number;
}
type Shape = Square | Reactangle | Circle;
function area(s: Shape) {
switch (s.kind) {
case "reactangle":
return s.height * s.width;
case "square":
return s.size * s.size;
// 添加上遗漏的分支即可
case "circle":
return Math.PI * s.r ** 2;
default:
return ((e: never) => {
throw new Error(e);
})(s);
}
}
// 打印出正确的值
console.log(area({ kind: "circle", r: 100 }));
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END