TypeScript 類型經驗本

這篇文章講解類型。莫要讓 TypeScript 成爲 AnyScript,學習類型也是從簡單複雜typescript

範型參數變量經常使用理解

  • T 表示 type 類型
  • P 表示 props 屬性
  • K/V key/value
  • U 經常使用的類型變量

類型中的關鍵字和操做符

複雜類型中經常使用的關鍵字和操做符json

  • keyof 至關於 Object.keys
  • in 至關於 for-in
  • ? 可選操做符
  • -? 可選取反
  • extends
    • interface/class 表示繼承
    • type 中表示約束
    • ...
  • []
    • 類型屬性訪問
    • 類型計算

簽名

定義函數的輸入和輸出api

嚴格的類型檢查

爲了更好的使用 TypeScript, 須要開啓嚴格的 TypeScript 代碼檢查:markdown

  • noImplicitAny 沒有隱式的 any 類型推斷
    • 錯誤提示:Parameter 'a' implicitly has an 'any' type.ts(7006)
  • strictNullChecks 嚴格的 null 檢查
    • 默認狀況下,值 null 和 undefined 可分配給任何其餘類型。
{
    "compilerOptions": {
        "noImplicitAny": true,
        "strictNullChecks": true,
    }
}
複製代碼

嚴格的 null 檢查 最佳實踐1 , 在處理空指針的狀況下,很是實用。app

type User = {
  name: string;
  age?: number; // 可選的屬性,不存在時,不能使用其上面的屬性和方法
}

const getUser = (user: User) => {
  console.log(user.name, user.age.toString()) // user.age 🐛 可能不存在可是調用方法
}
複製代碼

age 是可選的,可是在 console.log 中調用了 toString 方法。dom

  • ts: Object is possibly 'undefined'.ts(2532) 咱們可使用 ?. 來解決這個🐛,嚴格檢查
console.log(user.name, user.age?.toString())
複製代碼

基礎類型

  • boolean 布爾類型
  • string 字符串類型
  • void/null/undefined 三種空類型
  • any/any[] 類型
  • tuple 元祖類型
  • 枚舉類型
  • never/unknown
  • 函數類型
    • 函數/構造函數字面量類型
    • 函數調用類型
    • 構造函數簽名

按級別劃分類型

頂級類型 top type

  • any/unknown. 包含全部類型的集合。

底部類型 bottom type

  • never 空集合

從類型 type 引出接口 interface

在 TypeScript 中,使用 type 關鍵字,定義類型別名函數

type User = number | string; // 定義 number | string 的聯合類型爲 User
複製代碼

⚠️:別名 type 一旦定義定義就不能擴展本身,只能用 type 定一個其餘的類型。基於別名 type 自生不可擴展,引出 接口 interface 的概念就很合適了。oop

interface Global {
    api1: number
}
複製代碼

咱們想要擴展 Global 接口,就能夠直接從新定義(從新定義不是簡單的覆蓋行爲)學習

interface Global {
     api2: number
 }
複製代碼

api2接口屬性是補充在 Global 屬性上面的,而不是覆蓋以前定義的 api1。ui

TypeScript 對象類型 Object Types

對象類型應該是咱們最經常使用的複合類型在之一了。

定義對象類型的方式:

  • interface
  • type

他們的最主要的區別之一就是:能不能不產生新的類型的基礎上擴展本身。

可選/只讀的類型屬性

  • 可選: ?.<your option>
  • 只讀: readonly <you option>

索引類型

有時候,咱們不肯定屬性的名稱,此時咱們就能夠定義索引類型

interface User {
    [index: string]: any
}
複製代碼

index 表示索引,索引的類型是 string,屬性對應的類型是 any

interface 的類型擴展

  1. 從新定義接口,而後補充新的屬性,不產生一個新的接口
  2. 使用 extend 關鍵字補充,產生一個新的接口

type 的類型補充

  1. 使用 | 聯合類型,進行擴展,產生一個新的類型。

交叉類型

兩個類型交叉,將兩個不一樣類型組合成一個新的類型沒有重複的新的類型

type A = {
    name: string
    age: number
}

type B = {
    age: number
    sex: string
}

const C: A & B = {
    name: 'sdfd',
    age: 123,
    sex: 'male'
}

const D: A | B = {
    name: 'sdf',
    age: 123
}
複製代碼

類型進階

  • 泛型
  • 聯合類型
  • 交叉類型
  • 索引類型
  • 映射類型
  • 條件類型

重要的條件類型

extends 約束類型

extends關鍵字,在類型約束中起到重要做用。

語法

SomeType extends OtherType ? TrueType : FalseType;
複製代碼
  • 特色1: extends 關鍵字,本質是遍歷,每個屬性對比是子集,返回 TrueType, 不然返回 FalseType。 extends 表示條件
  • 特色2: 三目運算符 ? : , 分配類型

爲什是重要的條件類型?

  • 緣由是,他能夠衍生出不少的其餘的泛條件類型

本質很簡單,就是將是三目運算符,放在了類型的判斷中:(一個前提:條件是繼承關係)

T extends U ? X : Y
複製代碼

也就是說 子類型 T 是否是繼承自父類型 U若是是,取 X 類型,若是不是取 Y 類型。

既然是條件,那有 true/false 就很正常

type User = {
    name: string;
    age: number
}
declare function <T extends boolean>f(x: T): T extends true ? User : null;

// T 類型繼承 true 類型時,函數 f 的返回值是 User, 不然是 null

const a = f(Math.random() < 0.1); // User | number
const b = f( 1 < 2) // User
const c = f( 1 > 2) // null
複製代碼

泛條件類型

Exclude 在已有的類型中,排除指定的部分(子集關係 + never)

關於範型,這裏不討論。

type Exclude<T, U> = T extends U ? never : T;
複製代碼
  • exclude 示例
type Ex<T, U> = T extends U ? never : T

type Parent = {
    name: string;
    age: number;
}

type User = {
    name: string;
    age: number;
    sex: string;
}

// A 是 User 類型, 下面的 sex 的存在
const A: Ex<User, Parent> = {
    name: 'xiaoming',
    age: 234,
    sex: 'sdf' // Type '{ name: string; age: number; pa: number; ad: number; sex: string; }' is not assignable to type 'User'.
}
複製代碼

A 是 Ex<User, Parent> 類型,Parent 類型,不是 extends User,因此得 A 就是 User 類型.

示例

  • 一個類型能夠是 ID 或者 name, 根據不一樣的條件有不一樣的類型。
type IId = { id: number }

type IName = { name: string }

type NameOrId<T extends string | number> = T extends number ? IId :  IIName
複製代碼

擴展條件類型

從上面看了 Exclude 的源碼,是 子集 + never, 由此,咱們也能擴展其餘的類型:

  • 子集 + null
  • 子集 + undefined
  • 子集 + any(好像沒有必要)
type CNull<T, U> = T extends U ? null : T;
type CUndefined<T, U> = T extends U ? undefined : T;
type CAnd<T, U> = T extends U ? and : T;
複製代碼

參考

相關文章
相關標籤/搜索