TypeScript類型檢查機制


類型推斷

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM