日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

TypeScript 中的 Extends 怎么那么優秀啊?

來源: 責編: 時間:2024-05-07 09:11:49 161觀看
導讀在學習和使用 ts 的時候,有一個語法會大量的出現,他就是 extends。但是這個語法放到 ts 里,就顯得非常怪異,因為好多時候跟我們常規的理解看上去好像不太一樣,不就是一個繼承嗎,咋到處都在亂用啊?實際上,之所以怪,是因為在 ts

0zO28資訊網——每日最新資訊28at.com

在學習和使用 ts 的時候,有一個語法會大量的出現,他就是 extends。但是這個語法放到 ts 里,就顯得非常怪異,因為好多時候跟我們常規的理解看上去好像不太一樣,不就是一個繼承嗎,咋到處都在亂用啊?0zO28資訊網——每日最新資訊28at.com

實際上,之所以怪,是因為在 ts 中,extends 不只是要表達繼承的意思,他還有一些延展含義。0zO28資訊網——每日最新資訊28at.com

在 JS 核心進階中,我們在學習設計模式的時候,曾經提高過一個原則:里氏替換原則,該原則針對的是父類與子類之間的替換關系:任何使用父類實例的地方,都能夠使用子類實例完美替換。0zO28資訊網——每日最新資訊28at.com

class Person {  constructor(name) {    this.name = name  }  run(t) {    console.log(`${this.name} 跑了 ${t} 公里`);  }}class Student extends Person {  constructor(name, grade) {    super(name)    this.grade = grade  }}const p1 = new Person('Tom')p1.run(20)const s1 = new Student('Tom')s1.run(20)

這個案例中,我們能夠使用 s1 去替換 p1。而不會出現什么問題。0zO28資訊網——每日最新資訊28at.com

在 ts 的類型兼容性里,也符合這個原則。基于這個邏輯,我們就可以把 extends 作為一個判斷條件,來驗證你是否合理運用了里氏替換原則,從而衍生出它新的用法。0zO28資訊網——每日最新資訊28at.com

一、繼承

繼承的運用非常的常規。在面向對象的運用中,我們可以繼承一個父類。0zO28資訊網——每日最新資訊28at.com

class Parent {}class Children extends Parent {}

我們也可以在 interface 的類型聲明中,使用繼承。0zO28資訊網——每日最新資訊28at.com

interface Animal {  kind: string}interface Dog extends Animal {  bark(): void}

它等價于。0zO28資訊網——每日最新資訊28at.com

interface Dog {  kind: string  bark(): void}

二、泛型約束

我們先簡單來看一下這個東西是如何在泛型中使用的,然后再來結合里氏替換原則來分析它的邏輯。0zO28資訊網——每日最新資訊28at.com

interface Dispatch<T extends { type: string }> {  (action: T): T}

我們在定義 Dispatch 時需要傳入一個泛型,傳入的泛型類型必須與 {type: string} 符合里氏替換原則。意思就是說,要傳入該類型的子類型。0zO28資訊網——每日最新資訊28at.com

因此,我們可以傳入。0zO28資訊網——每日最新資訊28at.com

var action = {  type: 'get/list',  playload: 10}

也可以傳入。0zO28資訊網——每日最新資訊28at.com

var action = {  type: 'merge'}
var action = {  type: 'add',  value: { a: 1, b: 2 }}

從結論上來看,父類型的約束力度更小,子類型的約束力度更大。0zO28資訊網——每日最新資訊28at.com

三、條件判斷

我們可以可以繼續衍生,當子類型與父類型符合正常的繼承關系時,判斷結果為 true,否則為 false。0zO28資訊網——每日最新資訊28at.com

這里的繼承關系,表達的是一種替換關系,或者說是約束力度的縮小。0zO28資訊網——每日最新資訊28at.com

type C = A extends B ? string : number

這里表達的含義是,當 A 能夠替換 B 時,判斷結果為 true,否則,判斷結果為 false。0zO28資訊網——每日最新資訊28at.com

interface Person {  name: string}interface Yung extends Person {  gender: string}interface Student extends Yung {  age: string}

也就是說,當 A 作為 B 的子類型時,判斷結果為 true。0zO28資訊網——每日最新資訊28at.com

// 此時判斷結果為truetype C = Yung extends Person ? number : string // number
// 此時判斷結果為falsetype C = Yung extends Student ? number : string // string

也可以結合泛型使用。0zO28資訊網——每日最新資訊28at.com

type P<T> = T extends string ? string : numbertype Z = P<string> // string

當我們在使用泛型的時候,會出現一些問題,看一下這個例子。0zO28資訊網——每日最新資訊28at.com

type A = number | string extends string ? string : number // number

因為 string 的約束力度,比 number | string 更大,因此這里的條件判斷為 false,但是當我們通過泛型來做到同樣的事情時,情況就發生了變化。0zO28資訊網——每日最新資訊28at.com

type P<T> = T extends string ? string : numbertype A = P<number | string> // string | number

當我們用泛型傳遞時候,跟預想中的不太一樣,這里會把泛型傳入的 number 和 string 拆分之后在去運行 extends 判斷。因此最后的結果是 string | number。0zO28資訊網——每日最新資訊28at.com

聯合類型在泛型中的表現是分配之后再傳入。0zO28資訊網——每日最新資訊28at.com

在實踐中一定要警惕這個小小的差異。我們可以使用如下的方式避免這種先分配再傳入的規則。0zO28資訊網——每日最新資訊28at.com

type P<T> = [T] extends [string] ? string : numbertype A = P<number | string> // number

never 表示所有類型的子類型,因此也被看成是一個聯合類型,當我們在泛型中傳入 never 時也會同理出現同樣的問題。0zO28資訊網——每日最新資訊28at.com

type P<T> = T extends string ? string : number// 沒有類型可分配,直接返回 nevertype A = P<never> // never

注意他們的不同。0zO28資訊網——每日最新資訊28at.com

type P<T> = [T] extends [string] ? string : numbertype A = P<never> // string

四、定義一個 pick

現有一個對象 A 有很多個屬性,我希望重新定義一個新的對象 B,該對象的屬性是從 A 里挑選出來的,那么 B 的類型應該怎么定義呢。0zO28資訊網——每日最新資訊28at.com

interface A {  name: string;  age: number;  gender: number;  class: string}

當然,我們可以用常規的方式來定義,不過有的時候這樣會比較麻煩。0zO28資訊網——每日最新資訊28at.com

interface B {  name: string,  age: number}

我們也可以利用泛型和 extends,定義一個 Pick 類型。0zO28資訊網——每日最新資訊28at.com

type Pick<T, K extends keyof T> = {  [P in K]: T[P]}type B = Pick<A, 'name' | 'age'>

當我們在 Pick 中傳入 A 時, keyof A 的結果為 name | age | gender | class,因此 'name' | 'age' 是 keyof A 的子類型。0zO28資訊網——每日最新資訊28at.com

此時的 B 得到與上面寫法一樣的結果。0zO28資訊網——每日最新資訊28at.com

五、定義一個 Exclude

現在我有一個聯合類型。0zO28資訊網——每日最新資訊28at.com

type a = 'name' | 'age' | 'gender' | 'class'

我希望排除其中一個 name,得到一個新的聯合類型。0zO28資訊網——每日最新資訊28at.com

type b = 'age' | 'gender' | 'class'

此時我們可以定一個排除的泛型類型來做到這個事情。0zO28資訊網——每日最新資訊28at.com

type b = Exclude<a, 'name'>

這個 Exclude 是如何實現的呢?非常的簡單。0zO28資訊網——每日最新資訊28at.com

type Exclude<T, U> = T extends U ? never : Ttype b = Exclude<a, 'name'>

我們來分析一下,首先剛才我們已經知道,當傳入的泛型為聯合類型時,會先分配再傳入。0zO28資訊網——每日最新資訊28at.com

因此,此時傳入的聯合類型 a 會被拆分傳入。0zO28資訊網——每日最新資訊28at.com

也就是說,T exnteds U 的比較會變成。0zO28資訊網——每日最新資訊28at.com

// never'name' extends 'name' ? never : 'name'// age'age' extends 'name' ? never : 'age'// gender'gender' extends 'name' ? never : 'gender'// class'class' extends 'name' ? never : 'class'

所以通過這種方式,我們可以做到從聯合類型中排除指定的類型。0zO28資訊網——每日最新資訊28at.com

六、定義一個 Omit

Omit 是 Pick 的取反,表示挑選剩余的屬性組成新的對象。理解了 Pick 和 Exclude,這個理解起來非常容易。0zO28資訊網——每日最新資訊28at.com

type Omit<T, K> = Pick<T, Exclude<keyof T, K>>

使用:0zO28資訊網——每日最新資訊28at.com

interface A {  name: string,  age: number,  gender: number,  class: string}type B = Omit<A, 'name'>

等價于:0zO28資訊網——每日最新資訊28at.com

interface A {  age: number,  gender: number,  class: string}

大家可以自己分析一下 Omit 的實現原理,應該是沒有任何難度的。0zO28資訊網——每日最新資訊28at.com

七、最后

最后來個騷的,大家分析一下這玩意兒有什么用0zO28資訊網——每日最新資訊28at.com

type TypeString<T> =    T extends string ? "string" :    T extends number ? "number" :    T extends boolean ? "boolean" :    T extends undefined ? "undefined" :    T extends Function ? "function" :    "object";

本文鏈接:http://www.www897cc.com/showinfo-26-87003-0.htmlTypeScript 中的 Extends 怎么那么優秀啊?

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 逆向之旅:七個讓Python編程更糟糕的小技

下一篇: Fo-dicom,第一個基于.NET Standard 2.0 開發的DICOM開源庫

標簽:
  • 熱門焦點
Top 主站蜘蛛池模板: 吉木乃县| 鹿泉市| 延庆县| 九台市| 德令哈市| 综艺| 舞阳县| 金寨县| 新巴尔虎左旗| 榆中县| 南投市| 永泰县| 福鼎市| 基隆市| 保靖县| 葫芦岛市| 民和| 昭觉县| 阿坝县| 永顺县| 荥阳市| 原阳县| 祁阳县| 布尔津县| 平罗县| 梅州市| 台山市| 临夏县| 武乡县| 裕民县| 剑川县| 逊克县| 武乡县| 扎兰屯市| 伊吾县| 兰溪市| 高唐县| 天台县| 叙永县| 兴安盟| 平定县|