1. 程式人生 > 程式設計 >TypeScript學習筆記之型別窄化篇

TypeScript學習筆記之型別窄化篇

目錄
  • 前言
  • 型別推論
  • 真值窄化
  • 相等性窄化
  • in操作符窄化
  • instanceof窄化
  • 窄化的本質
  • 聯合型別的窄化
  • 總結

前言

TS最好用的地方就是強型別,隨之而來的就是型別窄化,摸魚的時候順道總結下.

型別推論

TypeScript裡,在有些沒有明確指出型別的地方,型別推論會幫助提供型別

Example:

let x = [0,1,null] // number

let x = Math.random() < 0.5 ? 100 : "helloword" // number|string

let x: Animal[] = [new Rhino(),new Elephant(),new Snake()]; // Rhino | Elephant | Snake

如果沒有找到最佳通用型別的話,型別推斷的結果為聯合陣列型別

聯合型別和型別守衛

Example:

// 聯合型別
type Types = number | string

function typeFn(type: Types,input: string): string {
  //  如果這樣寫就需要判斷type的型別
}

可以直接賦值型別推斷

let x:number|string = 1
x="tiedan"

如果不判斷會報錯

function typeFn(type: number | string,input: string) {
  // 報錯 運算子+號不能應用於 string 
  return new Array(type + 1).join("") + input
}

所以還得判斷

function typeFn(type: number | string,input: string) {
  // 型別守衛
  if (typeof type === 'number') {
    return new Array(type + 1).join(" ") + input
  }
  return type + input
}

型別的窄化就是根據判斷型別重新定義更具體的型別

那麼問題來了學這玩意幹嘛? 不香嗎?

個人觀點:

使用 TypeScript 可以幫你降低 弱語言的脆弱性,幫你減少由於不正確型別導致錯誤產生的風險,以及各種 Script 版本混雜造成錯誤的風險。

TypeScript 只是把高階語言的強型別這個最主要的特徵引入 JavaScript ,就解決了防止我們在編寫 JavaScript 程式碼時因為資料型別的轉換造成的意想不到的錯誤,增加了我們排查問題的困難性。

typeof的型別守衛:

"string"
"number"
"bigint" // ES10新增
"boolean"
"symbol" // ES6新增
"undefined"
"object"
"function"

注意: typeof null 等於 object

因此:

function strOrName(str: string | string[] | null) {
  if (typeof str === 'object') {
    for (const s of str) {
      // 報錯 因為str有可能是null
      conwww.cppcns.comsole.log(s)
    }
  } else if (typeof str === 'string') {
    console.log(str)
  } else {
    //......
  }
}

真值窄化

js的真值表很複雜,除以下的是false其餘的都是真。

0
NAN
""
0n // 0的bigint版本
null
undefined

避免null的錯誤可以利用真值窄化

// 利用真值判斷
if (str && typeof strs === 'object') {
  for (const s of strs) {
    console.log(s)
  }
}

或者這樣也行

function valOrName(values: number[] | undefined,filter: number): number[] | undefined {
  if (!values) {
    return values
  } else {
    return values.filter(x => x > filter)
  }
}

小結: 真值窄化幫助我們更好的處理null/undefined/0 等值

相等性窄化

想等性窄化就是利用 ===、 !== 、==、and、!= 等運算子進行窄化

Example1:

function strOrNum(x: string | number,y: string | boolean) {
  if (x === y) {
    // string
  } else {
    // string|number
  }
}

Examp客棧le2:

function strOrName(str: string | string[] | null) {
  if (str !== null) {
    if (typeof str === 'object') {
      for (const s of str) {
        console.log(s) // []
      }
    } else if (typeof str === 'string') {
      console.log(str) // string
    } else {
      // .....
    }
  }
}

Example3:

interface Types {
  value: number | null | undefined
}

function valOrType(type: Types,val: number) {
  // null和undefined 都是false 只能是number
  if (type.value != null) {
    type.value *= val
  }
}

in操作符窄化

in是檢查物件中是否有屬性,現在充當了一個 "type guard" 的角色。

Example:

interface A { a: number };
interface B { b: string };

function foo(x: A | B) {
    if ("a" in x) {
        return x.a;
    }
    return x.b;
}

instanceof窄化

instanceof表示式的右側必須屬於型別 any,或屬於可分配給 Function介面型別的型別。

Example:

function dateInval(x: Date | string) {
  if (x instanceof Date) {
    // Date
  } else {
    // string
  }
}

窄化的本質

窄化的本質是重新定義型別

Example:

function example() {
  let x: string | number | boolean
  x = Math.random() < 0.5
  if (Math.random() < 0.5) {
    x = 'hello' // string
  } else {
    x = 100 // number
  }
  return x; // string|number
}

聯合型別的窄化

Example1:

interface Shape {
  kind: "cirle" | "square",redius?: number
  sideLength?: number
}

// 報錯

function getArea(shape: Shape) {
	return Math.PI * shape.redius ** 2
}
// 窄化還是報錯

function getArea(shape: Shape) {
  if (shape.kind === 'cirle') {
    return Math.PI * shape.redius ** 2
  }
}
// 利用非空斷言闊以

function getArea(shape: Shape) {
  if (shape.kind === 'cirle') {
    return Math.PI * shape.redius! ** 2
  }
}

Example2:

interface Circle {
  kind: "cirle";
  redius: number;
}

interface Sqwww.cppcns.comuare {
  kind: "square";
  redius: number;
}

type Shape = Circle | Square

function getArea(shape: Shape) {
  if (shape.kind === 'cirle') { // 窄化
    return Math.PI * shape.redius ** 2
  }
}

// 或者

function getArea(shape: Shape) {
  switch (shape.kind) {
    case "cirle":
      return Math.PI * shape.redius ** 2
    case "square":
      return shape.sideLength ** 2
    default:
      const _example: never = shape
      return _example
  }
}

總結

到此這篇關於TypeScript學習筆記之型別窄化篇的文章就介紹到這了,更多相關TypeScript型別窄化內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!