国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

還可以這么玩?超實用 Typescript 內置類型與自定義類型

Astrian / 1978人閱讀

摘要:背景大家用過都清楚,很多時候我們需要提前聲明一個類型,再將類型賦予變量。上面使用到的和都是內置的類型別名。下面給大家介紹一下常用的內置類型,以及自行拓展的類型。

背景

大家用過 Typescript 都清楚,很多時候我們需要提前聲明一個類型,再將類型賦予變量。

例如在業務中,我們需要渲染一個表格,往往需要定義:

interface Row {
  user: string
  email: string
  id: number
  vip: boolean
  // ...
}

const tableDatas: Row[] = []
// ...

有時候我們也需要表格對應的搜索表單,需要其中一兩個搜索項,如果剛接觸 typescript 的同學可能會立刻這樣寫:

interface SearchModel {
  user?: string
  id?: number 
}  
const model: SearchModel = {
  user: "",
  id: undefined 
}

這樣寫會出現一個問題,如果后面id 類型要改成 string,我們需要改 2 處地方,不小心的話可能就會忘了改另外一處。所以,有些人會這樣寫:

interface SearchModel {
  user?: Row["user"]
  id?: Row["id"]
} 

這固然是一個解決方法,但事實上,我們前面已經定義了 Row 類型,這其實是可以更優雅地復用的:

const model: Partial = {
  user: "",
  id: undefined 
}
// 或者需要明確指定 key 的,可以
const model2: Partial>

這樣一來,很多情況下,我們可以盡量少地寫重復的類型,復用已有類型,讓代碼更加優雅容易維護。

上面使用到的 PartialPick 都是 typescript 內置的類型別名。下面給大家介紹一下 typescript 常用的內置類型,以及自行拓展的類型。

typescript 內置類型 Partial

將類型 T 的所有屬性標記為可選屬性

type Partial = {
    [P in keyof T]?: T[P];
};

使用場景:

// 賬號屬性
interface AccountInfo {
    name: string 
    email: string 
    age: number 
    vip: 0|1 // 1 是vip ,0 是非vip
}

// 當我們需要渲染一個賬號表格時,我們需要定義
const accountList: AccountInfo[] = []

// 但當我們需要查詢過濾賬號信息,需要通過表單,
// 但明顯我們可能并不一定需要用到所有屬性進行搜索,此時可以定義
const model: Partial = {
  name: "",
  vip: undefind
}
Required

與 Partial 相反,Required 將類型 T 的所有屬性標記為必選屬性

type Required = {
    [P in keyof T]-?: T[P];
};
Readonly

將所有屬性標記為 readonly, 即不能修改

type Readonly = {
    readonly [P in keyof T]: T[P];
};
Pick

從 T 中過濾出屬性 K

type Pick = {
    [P in K]: T[P];
};

使用場景:

interface AccountInfo {
  name: string 
  email: string 
  age: number 
  vip?: 0|1 // 1 是vip ,0 是非vip
}

type CoreInfo = Pick
/* 
{ 
  name: string
  email: stirng
}
*/
Record

標記對象的 key value類型

type Record = {
    [P in K]: T;
};

使用場景:

// 定義 學號(key)-賬號信息(value) 的對象
const accountMap: Record = {
  10001: {
    name: "xx",
    email: "xxxxx",
    // ...
  }    
}
const user: Record<"name"|"email", string> = {
    name: "", 
    email: ""
}
// 復雜點的類型推斷
function mapObject(obj: Record, f: (x: T) => U): Record

const names = { foo: "hello", bar: "world", baz: "bye" };
// 此處推斷 K, T 值為 string , U 為 number
const lengths = mapObject(names, s => s.length);  // { foo: number, bar: number, baz: number }
Exclude,Omit

移除 T 中的 U 屬性

type Exclude = T extends U ? never : T;

使用場景:

// "a" | "d"
type A = Exclude<"a"|"b"|"c"|"d" ,"b"|"c"|"e" >  

乍一看好像這個沒啥卵用,但是,我們通過一番操作,之后就可以得到 Pick 的反操作:

type Omit = Pick>

type NonCoreInfo = Omit
/*
{
  age: number 
  vip: 0|1,
}
*/
Extract

Exclude 的反操作,取 T,U兩者的交集屬性

type Extract = T extends U ? T : never;

使用 demo:

// "b"|"c"
type A = Extract<"a"|"b"|"c"|"d" ,"b"|"c"|"e" >  

這個看起來沒啥用,實際上還真沒啥卵用,應該是我才疏學淺,還沒發掘到其用途。

NonNullable

排除類型 T 的 null | undefined 屬性

type NonNullable = T extends null | undefined ? never : T;

使用 demo

type A = string | number | undefined 
type B = NonNullable // string | number

function f2(x: T, y: NonNullable) {
    let s1: string = x;  // Error, x 可能為 undefined
    let s2: string = y;  // Ok
}
Parameters

獲取一個函數的所有參數類型

// 此處使用 infer P 將參數定為待推斷類型
// T 符合函數特征時,返回參數類型,否則返回 never
type Parameters any> = T extends (...args: infer P) => any ? P : never;

使用demo:

interface IFunc {
  (person: IPerson, count: number): boolean
}

type P = Parameters // [IPerson, number]

const person01: P[0] = {
  // ...
}

另一種使用場景是,快速獲取未知函數的參數類型

import {somefun} from "somelib"
// 從其他庫導入的一個函數,獲取其參數類型
type SomeFuncParams = Parameters

// 內置函數
// [any, number?, number?]
type FillParams = Parameters
ConstructorParameters

類似于 Parameters, ConstructorParameters 獲取一個類的構造函數參數

type ConstructorParameters any> = T extends new (...args: infer P) => any ? P : never;

使用 demo:

// string | number | Date 
type DateConstrParams = ConstructorParameters
ReturnType

獲取函數類型 T 的返回類型

type ReturnType any> = T extends (...args: any) => infer R ? R : any;

使用方式和 Parameters 類似,不再贅述

InstanceType

獲取一個類的返回類型

type InstanceType any> = T extends new (...args: any) => infer R ? R : any;

使用方式和 ConstructorParameters 類似,不再贅述

自定義常用類型 Weaken

使用 typescript 有時候需要重寫一個庫提供的 interface 的某個屬性,但是重寫 interface 有可能會導致沖突:

interface Test {
  name: string
  say(word: string): string
}

interface Test2  extends Test{
  name: Test["name"] | number
}
// error: Type "string | number" is not assignable to type "string".

那么可以通過一些 type 來曲線救國實現我們的需求:

// 原理是,將 類型 T 的所有 K 屬性置為 any,
// 然后自定義 K 屬性的類型,
// 由于任何類型都可以賦予 any,所以不會產生沖突
type Weaken = {
  [P in keyof T]: P extends K ? any : T[P];
};


interface Test2  extends Weaken{
  name: Test["name"] | number
}
// ok
數組 轉換 成 union

有時候需要

const ALL_SUITS = ["hearts", "diamonds", "spades", "clubs"] as const; // TS 3.4
type SuitTuple = typeof ALL_SUITS; // readonly ["hearts", "diamonds", "spades", "clubs"]
type Suit = SuitTuple[number];  // union type : "hearts" | "diamonds" | "spades" | "clubs"
根據 enum 生成 union

enum 的 key 值 union

enum Weekday {
  Mon = 1
  Tue = 2
  Wed = 3
}
type WeekdayName = keyof typeof Weekday // "Mon" | "Tue" | "Wed"

enum 無法實現value-union , 但可以 object 的 value 值 union

const lit = (v: V) => v;
const Weekday = {
  MONDAY: lit(1),
  TUESDAY: lit(2),
  WEDNESDAY: lit(3)
}
type Weekday = (typeof Weekday)[keyof typeof Weekday] // 1|2|3

PartialRecord

前面我們講到了 Record 類型,我們會常用到

interface Model {
    name: string
    email: string
    id: number
    age: number
}

// 定義表單的校驗規則
const validateRules: Record = {
    name: {required: true, trigger: `blur`},
    id: {required: true, trigger: `blur`},
    email: {required: true, message: `...`},
    // error: Property age is missing in type...
}

這里出現了一個問題,validateRules 的 key 值必須和 Model 全部匹配,缺一不可,但實際上我們的表單可能只有其中的一兩項,這時候我們就需要:

type PartialRecord = Partial>

const validateRules: PartialRecord = {
   name: {required: true, trigger: `blur`} 
}

這個例子組合使用了 typescript 內置的 類型別名 PartialPartial

Unpacked

解壓抽離關鍵類型

type Unpacked =
    T extends (infer U)[] ? U :
    T extends (...args: any[]) => infer U ? U :
    T extends Promise ? U :
    T;

type T0 = Unpacked;  // string
type T1 = Unpacked;  // string
type T2 = Unpacked<() => string>;  // string
type T3 = Unpacked>;  // string
type T4 = Unpacked[]>;  // Promise
type T5 = Unpacked[]>>;  // string
總結

事實上,基于已有的類型別名,還有新推出的 infer 待推斷類型,可以探索出各種各樣的復雜組合玩法,這里不再多說,大家可以慢慢探索。

感謝閱讀!



本文首發于 github 博客   
如文章對你有幫助,你的 star 是對我最大的支持


插播廣告:   
深圳 Shopee 長期內推
崗位:前端,后端(要轉go),產品,UI,測試,安卓,IOS,運維 全都要。
薪酬福利:20K-50K

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/104449.html

相關文章

  • package.json 中 你不清楚的 browser,module,main 字段優先級

    摘要:本文就來說下這幾個字段的使用場景,以及同時存在這幾個字段時,他們之間的優先級。當存在和這種同名不同后綴的文件時,或者是會優先加載文件的。或者優先級是通過直接執行腳本只有字段有效。 browser VS module VS main 前端開發中使用到 npm 包那可算是家常便飯,而使用到 npm 包總免不了接觸到 package.json 包配置文件。 那么這里就有...

    caozhijian 評論0 收藏0
  • typescript - 一種思維方式

    摘要:怎么影響了我的思考方式對前端開發者來說,能強化了面向接口編程這一理念。使用的過程就是在加深理解的過程,確實面向接口編程天然和靜態類型更為親密。 電影《降臨》中有一個觀點,語言會影響人的思維方式,對于前端工程師來說,使用 typescript 開發無疑就是在嘗試換一種思維方式做事情。 其實直到最近,我才開始系統的學習 typescript ,前后大概花了一個月左右的時間。在這之前,我也在...

    CKJOKER 評論0 收藏0
  • TypeScript - 一種思維方式

    摘要:怎么影響了我的思考方式對前端開發者來說,能強化了面向接口編程這一理念。使用的過程就是在加深理解的過程,確實面向接口編程天然和靜態類型更為親密。摘要: 學會TS思考方式。 原文:TypeScript - 一種思維方式 作者:zhangwang Fundebug經授權轉載,版權歸原作者所有。 電影《降臨》中有一個觀點,語言會影響人的思維方式,對于前端工程師來說,使用 typescript 開...

    noONE 評論0 收藏0
  • VS Code上手與實用插件安利

    摘要:軟件跨平臺支持以及,運行流暢,可謂是微軟的良心之作微軟有這個宇宙最強,自然也不會弱宇宙最強編輯器說到代碼編輯器,我們有必要提一提還有。 原文鏈接:VS Code上手與超實用插件安利 工欲善其事必先利其器 Visual Studio Code (簡稱 VS Code / VSC) 是一款免費開源的現代化輕量級代碼編輯器,支持幾乎所有主流的開發語言的語法高亮、智能代碼補全、自定義熱鍵、括號...

    miracledan 評論0 收藏0
  • React Developers的10個實用神奇工具

    摘要:但是,如果必須更改實現方法以指向不同的數據庫,則單元測試將失敗,因為它們是耦合邏輯的實現細節。 showImg(https://segmentfault.com/img/bVbwf0d?w=786&h=155); showImg(https://segmentfault.com/img/bVbwf8m?w=941&h=578); React是一個用于構建用戶界面的JavaScript庫...

    Songlcy 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<