類型推斷
指不需要指定變量的類型,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");
