類型推斷
指不需要指定變量的類型,TS編譯器可以根據某些規則自動推斷出類型。
什么時候會有類型推斷?
- 聲明變量時沒有指定類型
- 函數默認參數
- 函數返回值
- ......
let a; // 這時自動推斷為any類型 let b = 1; // 推斷為number類型 let c = []; // 推斷為由any類型構成的數組 let d = (x=1) => x+1; // 函數傳參時,默認參數被推斷成number類型,返回值也會被推斷 let e = [1,null]; // 推斷出兼容所有數據的類型:number和null的聯合類型 有時候TS類型推斷不符合我們的預期,我們應該比編譯器更有信心它應該是什么類型,類型斷言就允許我們覆蓋TS的推論。 interface Foo{ bar: number } let foo: Foo = {} as Foo; // 如果一個對象按照接口的約定,需要有很多的屬性和方法,難以在聲明的時候定義完全。這時候可以用斷言 foo.bar = 1; // 具體的定義在這里
注意:類型斷言不能亂用,要對上下文環境有充足的預判,沒有任何根據的斷言會帶來安全隱患!
類型兼容
TS允許類型相互兼容的變量(函數、類等結構)相互賦值。
當一個類型Y可以被賦值給另一個類型X時,就認為類型X兼容Y,X為目標類型,Y為源類型。
兼容規則:
- 結構之間兼容:成員少的兼容成員多的
- 函數之間兼容:參數多的兼容參數少的
接口兼容性
interface X { a: any; b: any; } interface Y { a: any; b: any; c: any; } let x: X = {a:1,b:2}; let y: Y = {a:1,b:2,c:3}; x = y; // x兼容y 成員少的會兼容成員多的
函數兼容性
// 參數個數的兼容 type Handler = (a: number,b: number) => void; function hof(handler: Handler) { return handler } let handler1 = (a:number) => {}; hof(handler1); // 一個參數可以兼容 let handler2 = (a: number,b: number,c: number) => {}; // hof(handler2); // 三個參數不被兼容 // 可選參數和剩余參數的兼容 let a1 = (p1: number, p2: number) => {}; let b1 = (p1?: number, p2?: number) => {}; let c1 = (...args: number[]) => {}; a1 = b1; a1 = c1; // b1 = a1; // 可選參數不能被兼容。需要將tsconfig.json中“strictFunctionTypes”置為false即可 // b1 = c1; c1 = a1; c1 = b1;
類的兼容性
兩個定義不同的類互不兼容,子類在繼承父類后沒有做改動,可以兼容父類。
泛型的兼容性
兩個定義完全一樣的泛型函數相互兼容
類型保護
TypeScript能夠在特定的區塊中保證變量屬於某種確定的類型。可以在此區塊中放心地訪問此類型的屬性和方法。
比如,我們要判斷一個對象是否含有某個方法
interface OBJ { name: string, age: number, sex: boolean } let obj: OBJ = { name: "typescript", age: 10, sex: true, }; if(obj.sex) // obj中有sex屬性,所以OK { console.log("has sex"); } // if(obj.bac) {} // obj中沒有bac屬性,此處報錯。
我們有四種提供類型保護的方式:
- instanceof 用於判斷一個實例是否屬於某個類
- in 判斷一個屬性/方法是否屬於某個對象
- typeof 用於判斷基本類型
- 類型保護函數 當判斷邏輯復雜時,可以自定義判斷函數
class Java { helloJava(){ console.log("hello java"); } java: any; } class JavaScript { hellloJavaScript(){ console.log("hello javascript"); } javascript: any; } // 類型保護函數 注意參數類型 和 返回值類型 的關系 function isJava(lang: Java|JavaScript):lang is Java { return (lang as Java).helloJava !== undefined } function getLanguage(type: number,x: string|number|boolean) { let lang = type === 1 ? new Java() : new JavaScript(); // instanceof 判斷lang是否屬於Java類 if(lang instanceof Java) { lang.helloJava(); // 在這個區塊中,能夠保證lang一定是java的實例,調用自己的方法 }else { lang.hellloJavaScript(); // 這個區塊中,一定能夠保證lang是JavaScript的實例 } // in “helloJava”方法是否屬於lang對象 if("helloJava" in lang) { lang.java; // 在這個區塊中能夠保證,lang是java的實例 }else { lang.javascript // 這個區塊中能夠保證lang是JavaScript的實例 } // typeof 用於判斷基本類型 if(typeof x === "string") { x.length // 程序進入這個區塊,能夠保證x是string類型。可以調用字符串原生方法 }else if(typeof x === "number") { x.toFixed(2); // 在這里能夠調用數字的原生方法 }else { x = !x; } // 類型保護函數 在定義的時候,注意返回值的類型和參數類型的關系 if(isJava(lang)) { lang.helloJava(); }else { lang.hellloJavaScript(); } } getLanguage(2,"str");