類型檢查機制: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
三、類型保護機制
因為不知道程序運行時會傳入什么參數,所以得在每一處都加上類型斷言。

enum Type {Strong, weak} class Java{ helloJava(){ console.log("hello Java") } } class JavaScript{ helloJavaScript(){ console.log("Hello JavaScript"); } } //用類型斷言解決報錯 function getLanguage(type:Type){ let lang = type===Type.Strong?new Java():new JavaScript() //創建實例之后運行實例的打印的方法 if((lang as Java).helloJava){ (lang as Java).helloJava(); }else{ (lang as JavaScript).helloJavaScript() } return lang } getLanguage(Type.Strong)
代碼可讀性差,類型保護機制來解決這個問題。
類型保護:TypeScript能夠在特定的區塊中保證變量屬於某種確定的類型。
可以在此區塊中放心地引用此類型的屬性,或者調用此類型的方法。
4種創建特殊區塊的方法。
1、instanceof
function getLanguage(type:Type){ let lang = type===Type.Strong?new Java():new JavaScript() // 第一種 instanceof if(lang instanceof Java){ lang.helloJava() }else{ lang.helloJavaScript() } return lang }
2, in
判斷某個屬性是否屬於某個對象
在兩個類中分別加入一個屬性java和javascript
enum Type {Strong, weak} class Java{ helloJava(){ console.log("hello Java") } java :any } class JavaScript{ helloJavaScript(){ console.log("Hello JavaScript"); } javascript: any }
function getLanguage(type:Type){ let lang = type===Type.Strong?new Java():new JavaScript() //第二種 in關鍵字,判斷屬性是否屬於某個對象 if('java' in lang){ lang.helloJava() }else{ lang.helloJavaScript() } return lang }
3, typeof類型保護
判斷基本類型
function getLanguage(type:Type, x:string | number){ let lang = type===Type.Strong?new Java():new JavaScript() //第三種 typeof 判斷基本類型 //新加函數參數x類型是聯合類型string | number if(typeof x === 'string'){ x.length //調string類型的屬性 }else{ x.toFixed() //調number類型的方法 } return lang }
4,自定義類型保護函數
通過創建類型保護函數isJava()判斷對象的類型
function isJava(lang: Java | JavaScript ):lang is Java{ return (lang as Java).helloJava !== undefined } function getLanguage(type:Type, x:string | number){ let lang = type===Type.Strong?new Java():new JavaScript() //第四種 類型保護函數 if(isJava(lang)){ lang.helloJava() }else{ lang.helloJavaScript() } return lang }