9.类型保护

133 阅读6分钟

9.类型保护

  • 类型保护就是一些表达式,他们在编译的时候就能通过类型信息确保某个作用域内变量的类型

  • 类型保护就是能够通过关键字判断出分支中的类型

9.1 typeof 类型保护


function double(input: string | number | boolean) {

if (typeof input === 'string') {

return input + input;

} else {

if (typeof input === 'number') {

return input * 2;

} else {

return !input;

}

}

}

9.2 instanceof类型保护


class Animal {

name!: string;

}

class Bird extends Animal {

swing!: number

}

function getName(animal: Animal) {

if (animal instanceof Bird) {

console.log(animal.swing);

} else {

console.log(animal.name);

}

}

9.3 null保护

  • 如果开启了strictNullChecks选项,那么对于可能为null的变量不能调用它上面的方法和属性

function getFirstLetter(s: string | null) {

//第一种方式是加上null判断

if (s == null) {

return '';

}

//第二种处理是增加一个或的处理

s = s || '';

return s.charAt(0);

}

//它并不能处理一些复杂的判断,需要加非空断言操作符

function getFirstLetter2(s: string | null) {

function log() {

console.log(s!.trim());

}

s = s || '';

log();

return s.charAt(0);

}

9.4 链判断运算符

  • 链判断运算符是一种先检查属性是否存在,再尝试访问该属性的运算符,其符号为 ?.

  • 如果运算符左侧的操作数 ?. 计算为 undefined 或 null,则表达式求值为 undefined 。否则,正常触发目标属性访问,方法或函数调用。

  • 链判断运算符处于stage1 ts也不支持


a?.b; //如果a是null/undefined,那么返回undefined,否则返回a.b的值.

a == null ? undefined : a.b;

a?.[x]; //如果a是null/undefined,那么返回undefined,否则返回a[x]的值

a == null ? undefined : a[x];

a?.b(); // 如果a是null/undefined,那么返回undefined

a == null ? undefined : a.b(); //如果a.b不函数的话抛类型错误异常,否则计算a.b()的结果

a?.(); //如果a是null/undefined,那么返回undefined

a == null ? undefined : a(); //如果A不是函数会抛出类型错误

//否则 调用a这个函数

9.5 可辨识的联合类型

  • 就是利用联合类型中的共有字段进行类型保护的一种技巧

  • 相同字段的不同取值就是可辨识


interface WarningButton{

class:'warning',

text1:'修改'

}

interface DangerButton{

class:'danger',

text2:'删除'

}

type Button = WarningButton|DangerButton;

function getButton(button:Button){

if(button.class=='warning'){

console.log(button.text1);

}

if(button.class=='danger'){

console.log(button.text2);

}

}

  • 类型字面量+可辨识联合类型

interface User{

username:string

}

type Action = {

type:'add',

payload:User

} | {

type: 'delete'

payload: number

}

const UserReducer = (action: Action) => {

switch (action.type) {

case "add":

let user: User = action.payload;

break;

case "delete":

let id: number = action.payload;

break;

default:

break;

}

};

9.6 in操作符

  • in 运算符可以被用于参数类型的判断

interface Bird {

swing: number;

}

interface Dog {

leg: number;

}

function getNumber(x: Bird | Dog) {

if ("swing" in x) {

return x.swing;

}

return x.leg;

}

9.7 自定义的类型保护

  • TypeScript 里的类型保护本质上就是一些表达式,它们会在运行时检查类型信息,以确保在某个作用域里的类型是符合预期的

  • type is Type1Class就是类型谓词

  • 谓词为 parameterName is Type这种形式,parameterName必须是来自于当前函数签名里的一个参数名

  • 每当使用一些变量调用isType1时,如果原始类型兼容,TypeScript会将该变量缩小到该特定类型


function isType1(type: Type1Class | Type2Class): type is Type1Class {

return (<Type1Class>type).func1 !== undefined;

}


interface Bird {

swing: number;//2

}

interface Dog {

leg: number;//4

}

//自定义的类型保护了 TODO

/* function isType(type:Type1|Type2):type is Type1{

} */

//类型谓词 parameterName is Type 哪个参数是什么类型

function isBird(y:Bird|Dog):y is Bird{

return (y as Bird).swing == 2;

}

function getAnimal(x: Bird | Dog) {

if (isBird(x)) {

return x.swing;

}

return x.leg;

}

let a1:Bird={

swing:2

}

let a2:Dog={

leg:4

}

console.log(getAnimal(a1)) //2

console.log(getAnimal(a2)) //4

9.8 unknown

  • TypeScript 3.0 引入了新的unknown 类型,它是 any 类型对应的安全类型

  • unknown 和 any 的主要区别是 unknown 类型会更加严格:在对 unknown 类型的值执行大多数操作之前,我们必须进行某种形式的检查。而在对 any 类型的值执行操作之前,我们不必进行任何检查

9.8.1 any 类型

  • 在 TypeScript 中,任何类型都可以被归为 any 类型。这让 any 类型成为了类型系统的 顶级类型 (也被称作 全局超级类型)。

  • TypeScript允许我们对 any 类型的值执行任何操作,而无需事先执行任何形式的检查


value = true; // OK

value = 42; // OK

value = "Hello World"; // OK

value = []; // OK

value = {}; // OK

value = Math.random; // OK

value = null; // OK

value = undefined; // OK

let value: any;

value.foo.bar; // OK

value.trim(); // OK

value(); // OK

new value(); // OK

9.8.2 unknown 类型

  • 就像所有类型都可以被归为 any,所有类型也都可以被归为 unknown。这使得 unknown 成为 TypeScript 类型系统的另一种顶级类型(另一种是 any)

  • 任何类型都可以赋值给unknown类型


let value: unknown;

value = true; // OK

value = 42; // OK

value = "Hello World"; // OK

value = []; // OK

value = {}; // OK

value = Math.random; // OK

value = null; // OK

value = undefined; // OK

value = new TypeError(); // OK

  • unknown类型只能被赋值给any类型和unknown类型本身

let value: unknown;

let value1: unknown = value; // OK

let value2: any = value; // OK

let value3: boolean = value; // Error

let value4: number = value; // Error

let value5: string = value; // Error

let value6: object = value; // Error

let value7: any[] = value; // Error

let value8: Function = value; // Error

9.8.3 缩小 unknown 类型范围

  • 如果没有类型断言或类型细化时,不能在unknown上面进行任何操作

  • typeof

  • instanceof

  • 自定义类型保护函数

  • 可以对 unknown 类型使用类型断言


let value2:unknown;

//如果想调用unknown上的方法和属性

value2 = 'hello';

// 断言

console.log((value2 as string).length);

//typeof

if(typeof value2 == 'string'){

console.log(value2.length);

}

9.8.4 联合类型中的 unknown 类型

  • 在联合类型中,unknown 类型会吸收任何类型。这就意味着如果任一组成类型是 unknown,联合类型也会相当于 unknown:

type UnionType1 = unknown | null; // unknown

type UnionType2 = unknown | undefined; // unknown

type UnionType3 = unknown | string; // unknown

type UnionType4 = unknown | number[]; // unknown

9.8.5 交叉类型中的 unknown 类型

  • 在交叉类型中,任何类型都可以吸收 unknown 类型。这意味着将任何类型与 unknown 相交不会改变结果类型

type IntersectionType1 = unknown & null; // null

type IntersectionType2 = unknown & undefined; // undefined

type IntersectionType3 = unknown & string; // string

type IntersectionType4 = unknown & number[]; // number[]

type IntersectionType5 = unknown & any; // any

  • 交叉类型

//交叉类型

interface A{name:string,c:number}

interface B{age:number,c:number}

let a:A;

let b:B;

type C = A&B;

let c:C = {name:'zhufeng',age:10,c:10};

a=c;

b=c;

type AA = string|number;

type BB = string|boolean;

type CC = AA&BB;

let d:CC='11';

// let e:CC=11; // Type 'number' is not assignable to type 'string'.

9.8.6 never是unknown的子类型


type isNever = never extends unknown?true:false;

let e:isNever=true

9.8.7 keyof unknown 等于never


type isNever2 = keyof unknown;

9.8.8 只能对unknown进行等或不等操作,不能进行其它操作


let aa:unknown

let bb:unknown;

console.log(aa ===bb);

console.log(aa !== bb);

//let cc = aa+bb; //Object is of type 'unknown'

9.8.9 不能做任何操作

  • 不能访问属性

  • 不能作为函数调用

  • 不能当作类的构造函数不能创建实例


let aa:unknown

// aa.name

// aa();

// new aa();

9.8.10 映射属性

  • 如果映射类型遍历的时候是unknown,不会映射属性

type getType<T> = {

[P in keyof T]:number

}

type t = getType<unknown> //{}

type t2 ={

name:'hehe',

age:13

}

type t3 = getType<t2> // {name: number;age: number;}