在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
一、类型守卫类型保护是可执行运行时检查的一种表达式,用于确保该类型在一定的范围内。 换句话说,类型保护可以保证一个字符串是一个字符串,尽管它的值也可以是一个数值。类型保护与特性检测并不是完全不同,其主要思想是尝试检测属性、方法或原型,以确定如何处理值。目前主要有四种的方式来实现类型保护: interface Admin {
name: string;
privileges: string[];
}
interface Employee {
name: string;
startDate: Date;
}
type UnknownEmployee = Employee | Admin;
function printEmployeeInformation(emp: UnknownEmployee) {
if ("privileges" in emp) {
console.log("Privileges: " + emp.privileges);
}
if ("startDate" in emp) {
console.log("Start Date: " + emp.startDate);
}
}
2、typeof 关键字 function padLeft(value: string, padding: string | number) {
if (typeof padding === "number") {
return Array(padding + 1).join(" ") + value;
}
if (typeof padding === "string") {
return padding + value;
}
throw new Error(`Expected string or number, got '${padding}'.`);
}
typeof 类型保护只支持两种形式:typeof v === "typename" 和 typeof v !== typename ,"typename" 必须是 "number" , "string" , "boolean" 或 "symbol" 。 但是 TypeScript 并不会阻止你与其它字符串比较,语言不会把那些表达式识别为类型保护。3、instanceof 关键字 4、自定义类型保护的类型谓词 总结:简言之,类型守卫就是加一层判断,对于不同的判断进行不同的业务处理。
二、联合类型1、联合类型:联合类型(Union Types)可以通过管道 ( | ) 将变量设置多种类型,赋值时可以根据设置的类型来赋值。 注意:只能赋值指定的类型,如果赋值其它类型就会报错。 创建联合类型的语法格式如下:Type1|Type2|Type3 比如:可以用 | 来支持多种类型 let x: number | null | undefined;
x = 1; // 运行正确
x = undefined; // 运行正确
x = null; // 运行正确
联合类型通常与
null 或 undefined 一起使用。例如,这里 name 的类型是 string | undefined 意味着可以将 string 或 undefined 的值传递给sayHello 函数。
const sayHello = (name: string | undefined) => {};
sayHello("***");
sayHello(undefined);
通过这个示例我们可以知道类型 A 和类型 B 联合后的类型是同时接受 A 和 B 值的类型。此外,对于联合类型来说,你可能会遇到以下的用法: let num: 1 | 2 = 1;
type EventNames = 'click' | 'scroll' | 'mousemove';
以上示例中的 TypeScript 可辨识联合(Discriminated Unions)类型,也称为代数数据类型或标签联合类型。它包含 3 个要点:可辨识、联合类型和类型守卫。 这种类型的本质是结合联合类型和字面量类型的一种类型保护方法。如果一个类型是多个类型的联合类型,且多个类型含有一个公共属性,那么就可以利用这个公共属性,来创建不同的类型保护区块。 enum CarTransmission {
Automatic = 200,
Manual = 300
}
interface Motorcycle {
vType: "motorcycle"; // discriminant
make: number; // year
}
interface Car {
vType: "car"; // discriminant
transmission: CarTransmission
}
interface Truck {
vType: "truck"; // discriminant
capacity: number; // in tons
}
在上述代码中,我们分别定义了 (2)联合类型:基于前面定义了三个接口,我们可以创建一个 type Vehicle = Motorcycle | Car | Truck;
现在我们就可以开始使用 (3)类型守卫:下面我们来定义一个 const EVALUATION_FACTOR = Math.PI;
function evaluatePrice(vehicle: Vehicle) {
return vehicle.capacity * EVALUATION_FACTOR;
}
const myTruck: Truck = { vType: "truck", capacity: 9.5 };
evaluatePrice(myTruck);
// 对于以上代码,TypeScript 编译器将会提示以下错误信息:
Property 'capacity' does not exist on type 'Vehicle'.
Property 'capacity' does not exist on type 'Motorcycle'.
原因是在 Motorcycle 接口中,并不存在
capacity 属性,而对于 Car 接口来说,它也不存在 capacity 属性。那么,现在我们应该如何解决以上问题呢?这时,我们可以使用类型守卫。下面我们来重构一下前面定义的 evaluatePrice 方法,重构后的代码如下:
function evaluatePrice(vehicle: Vehicle) {
switch(vehicle.vType) {
case "car":
return vehicle.transmission * EVALUATION_FACTOR;
case "truck":
return vehicle.capacity * EVALUATION_FACTOR;
case "motorcycle":
return vehicle.make * EVALUATION_FACTOR;
}
}
在以上代码中,我们使用 所以从这里也可以看出所谓类型守卫就是确保所使用的类型均可以正常使用,从而针对不同类型,使用不同的业务处理。
三、交叉类型 在 TypeScript 中交叉类型是将多个类型合并为一个类型。通过 type PartialPointX = { x: number; };
type Point = PartialPointX & { y: number; };
let point: Point = {
x: 1,
y: 1
}
在上面代码中我们先定义了 1、同名基础类型属性的合并 那么问题来了,假设在合并多个类型的过程中,刚好出现某些类型存在相同的成员,但对应的类型又不一致,比如: interface X { c: string; d: string; } interface Y { c: number; e: string } type XY = X & Y; type YX = Y & X; 在上面的代码中,接口 X 和接口 Y 都含有一个相同的成员 c,但它们的类型不一致。对于这种情况,此时 XY 类型或 YX 类型中成员 c 的类型是不是可以是
为什么接口 X 和接口 Y 混入后,成员 c 的类型会变成
never 呢?这是因为混入后成员 c 的类型为 string & number ,即成员 c 的类型既可以是 string 类型又可以是 number 类型。很明显这种类型是不存在的,所以混入后成员 c 的类型为 never 。2、同名非基础类型属性的合并 在上面示例中,刚好接口 X 和接口 Y 中内部成员 c 的类型都是基本数据类型,那么如果是非基本数据类型的话,又会是什么情形。我们来看个具体的例子: interface D { d: boolean; } interface E { e: string; } interface F { f: number; } interface A { x: D; } interface B { x: E; } interface C { x: F; } type ABC = A & B & C; let abc: ABC = { x: { d: true, e: '***', f: 666 } }; console.log('abc:', abc); 以上代码可以成功运行,且 abc 就为上述结果。由此可知:在混入多个类型时,若存在相同的成员,且成员类型为非基本数据类型,那么是可以成功合并。 总结: (1)同名基础类型属性合并:string & number,这样的值不存在,所以是 never; (2)同名非基础类型属性合并:比如 { a: string } & { b: number },可以成功合并为 { a: string, b: number }。 |
请发表评论