TypeScript类型检查机制

ChaITSimpleLove 2020-06-09

类型检查机制:TypeScript编译器在做类型检查时,所秉承的一些原则。

作用:辅助开发,提高开发效率。

一、类型推断

不需要指定变量的类型(函数的返回值类型),TypeScript可以根据某些规则自动地为其推断出一个类型。

1,基础类型推断

let a //let a: any
let b = 1 //let b: number
let c = [] //let c: any[]
let c2 = [1] //let c2: number[]

//设置函数默认参数
//确定函数返回值的时候
//let function1: (x?: number) => number
let function1 =(x=1)=> x+1  //x=>number //function1返回number类型

2,最佳通用类型推断

//最佳通用类型推断
//从多个类型推断出一个类型的时候,尽可能的兼容类型

let arr = [1,null] //let arr: (number | null)[]

3,上下文类型推断

上面两种类型推断都是从右向左的推断,也就是根据表达式右侧的值推断表达式左边变量的类型。还有一种类型推断是从左到右。这就是上下文类型推断。

上下文类型推断通常发生在事件处理中。

window.onkeydown = (event)=>{
    console.log(evevt.button)
}

用类型断言

interface Foo{
    bar:number
}
// let foo = {} as Foo
// foo.bar =1;

//推荐
let foo: Foo ={
    bar: 1
}

二、类型兼容性

结构之间兼容:成员少的兼容成员多的

函数之间兼容:参数多的兼容参数少的

 1,接口兼容性

属性少的兼容属性多的

//类型兼容性
/**
 * X兼容Y:X(目标类型) = Y(源类型)
 */

 //接口兼容性
 interface X{
     a:any;
     b:any;
 }

 interface Y{
     a:any;
     b:any;
     c:any;
 }

 let x1:X ={a:1,b:2};
 let y1:Y={a:1,b:2,c:3}

 x1 = y1 //X可以兼容Y
//  y1 =x1 //Property ‘c‘ is missing in type ‘X‘ but required in type ‘Y‘.

2,函数的兼容性

 两个函数相互赋值的情况,即函数作为参数的情况。

1, 目标函数的参数个数一定要等于多于原函数的个数

函数中含义可选参数或者剩余参数的时候,也会遵循其他原则

//1)参数个数
let handler1 = (a:number) =>{}
hof(handler1)
let handler2 = (a:number, b:number) =>{}
hof(handler2)
let handler3 = (a:number, b:number, c:number) =>{}
// hof(handler3) //类型“(a: number, b: number, c: number) => void”的参数不能赋给类型“Handler”的参数。


//可选参数和剩余参数
let functionA=(p1:number,p2:number)=>{} //固定参数
let functionB=(p1?:number,p2?:number)=>{} //可选参数
let functionC=(...args:number[])=>{} //剩余参数

//1,固定参数可以兼容可选参数和剩余参数
functionA=functionB //固定参数可以兼容可选参数
functionA=functionC //固定参数可以兼容剩余参数

//2,可选参数不兼容固定参数和剩余参数
// functionB = functionA  //不能将类型“undefined”分配给类型“number”
// functionB = functionC  //不能将类型“undefined”分配给类型“number”

// 可以通过设置 strictFunctionTypes: false来实现兼容


 // functionB = functionA
 // functionB = functionC

//3,剩余参数可以兼容固定参数和可选参数
functionC = functionA
functionC = functionB

2,参数类型

//2)参数类型
let handler4 =(a:string) =>{}
// hof(handler4)  //类型不兼容,不能将类型“number”分配给类型“string”。

interface Point3D{
    x:number;
    y:number;
    z:number;
}
interface Point2D{
    x:number;
    y:number;
}
let p3d =(point:Point3D) =>{}
let p2d =(point:Point2D) =>{}
p3d = p2d; 
// p2d = p3d; //不兼容 ////Property ‘z‘ is missing in type ‘Point2D‘ but required in type ‘Point3D‘.


//对比接口的兼容性
let i3d:Point3D = {x:1,y:1,z:1};
let i2d:Point2D = {x:1,y:1};
i2d = i3d
// i3d = i2d //不兼容 //Property ‘z‘ is missing in type ‘Point2D‘ but required in type ‘Point3D‘.

3,返回值类型

//3) 返回值类型
//目标函数的返回值类型必须与源函数的返回值类型相同或为其子类型
let rf1 = ()=>({name:"Alice"});
let rf2 = ()=>({name:"Alice",location:"Beijing"});
rf1 = rf2;
// rf2 = rf1; //Property ‘location‘ is missing in type ‘{ name: string; }‘ but required in type ‘{ name: string; location: string; }‘.

//函数重载

function overload(a:number,b:number):number
function overload(a:string,b:string):string
function overload(a:any,b:any):any {}

函数重载:

重载列表中的函数是目标函数,具体实现是源函数,编译器查找重载列表,使用第一个匹配的定义执行执行函数。

3,枚举的兼容性

//枚举类型
//枚举类型和数值类型完全兼容
enum Fruit {Apple, banana}
enum Color {Red, Yellow}
let fruit:Fruit.Apple =4

let no:number = Fruit.Apple
// let color:Color.Red = Fruit.Apple 枚举类型之间不兼容

4,类的兼容性

 静态成员和构造函数不参与两个类兼容性比较

//类的兼容性
//静态成员和构造函数不参与两个类的兼容性比较
class A{
    constructor(p:number,q:number){}
    id:number =1;
}

class B{
    static s =1;
    id:number =2
    constructor(p:number){}
}

let aa = new A(1,2);
let bb = new B(1);
aa = bb;
bb =aa;

如果类中有私有成员,两个类就不兼容了

//类的兼容性
//静态成员和构造函数不参与两个类的兼容性比较
class A{
    constructor(p:number,q:number){}
    id:number =1;
    private name:string = ‘‘
}

class B{
    static s =1;
    id:number =2
    constructor(p:number){}
    private name:string = ‘‘
}

let aa = new A(1,2);
let bb = new B(1);
// aa = bb; //不能将类型“B”分配给类型“A”。类型具有私有属性“name”的单独声明
// bb =aa; //不能将类型“A”分配给类型“B”。类型具有私有属性“name”的单独声明

类有私有成员的时候,只有父类和子类直接可以相互兼容

class A{
    constructor(p:number,q:number){}
    id:number =1;
    private name:string = ‘‘
}

let aa = new A(1,2);

class AA extends A{
}
let aaa = new AA(1,2)
aa=aaa 
aaa =aa

5,泛型的兼容性

//泛型的兼容性
interface Empty<T>{
    // value:T //只有类型参数T被接口成员使用了以后才会影响泛型的兼容性
}
let intObj1:Empty<number> = {}
let intObj2:Empty<string> = {}
intObj1 = intObj2

泛型函数

//泛型函数
//两个泛型函数定义相同,没有指定类型参数,它们之间也可以相互兼容
let log1 = <T> (x:T):T=>{
    console.log(‘x‘);
    return x;
}

let log2 = <U> (x:U):U=>{
    console.log(‘y‘);
    return x;
}
log1= log2 

三、类型保护

相关推荐