成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

TypeScript 中的 Extends 怎么那么優(yōu)秀啊?

開發(fā) 后端
在 JS 核心進(jìn)階中,我們在學(xué)習(xí)設(shè)計模式的時候,曾經(jīng)提高過一個原則:里氏替換原則,該原則針對的是父類與子類之間的替換關(guān)系:任何使用父類實例的地方,都能夠使用子類實例完美替換。

在學(xué)習(xí)和使用 ts 的時候,有一個語法會大量的出現(xiàn),他就是 extends。但是這個語法放到 ts 里,就顯得非常怪異,因為好多時候跟我們常規(guī)的理解看上去好像不太一樣,不就是一個繼承嗎,咋到處都在亂用啊?

實際上,之所以怪,是因為在 ts 中,extends 不只是要表達(dá)繼承的意思,他還有一些延展含義。

在 JS 核心進(jìn)階中,我們在學(xué)習(xí)設(shè)計模式的時候,曾經(jīng)提高過一個原則:里氏替換原則,該原則針對的是父類與子類之間的替換關(guān)系:任何使用父類實例的地方,都能夠使用子類實例完美替換。

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。而不會出現(xiàn)什么問題。

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

一、繼承

繼承的運用非常的常規(guī)。在面向?qū)ο蟮倪\用中,我們可以繼承一個父類。

class Parent {}
class Children extends Parent {}

我們也可以在 interface 的類型聲明中,使用繼承。

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

它等價于。

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

二、泛型約束

我們先簡單來看一下這個東西是如何在泛型中使用的,然后再來結(jié)合里氏替換原則來分析它的邏輯。

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

我們在定義 Dispatch 時需要傳入一個泛型,傳入的泛型類型必須與 {type: string} 符合里氏替換原則。意思就是說,要傳入該類型的子類型。

因此,我們可以傳入。

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

也可以傳入。

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

從結(jié)論上來看,父類型的約束力度更小,子類型的約束力度更大。

三、條件判斷

我們可以可以繼續(xù)衍生,當(dāng)子類型與父類型符合正常的繼承關(guān)系時,判斷結(jié)果為 true,否則為 false。

這里的繼承關(guān)系,表達(dá)的是一種替換關(guān)系,或者說是約束力度的縮小。

type C = A extends B ? string : number

這里表達(dá)的含義是,當(dāng) A 能夠替換 B 時,判斷結(jié)果為 true,否則,判斷結(jié)果為 false。

interface Person {
  name: string
}

interface Yung extends Person {
  gender: string
}

interface Student extends Yung {
  age: string
}

也就是說,當(dāng) A 作為 B 的子類型時,判斷結(jié)果為 true。

// 此時判斷結(jié)果為true
type C = Yung extends Person ? number : string // number
// 此時判斷結(jié)果為false
type C = Yung extends Student ? number : string // string

也可以結(jié)合泛型使用。

type P<T> = T extends string ? string : number

type Z = P<string> // string

當(dāng)我們在使用泛型的時候,會出現(xiàn)一些問題,看一下這個例子。

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

因為 string 的約束力度,比 number | string 更大,因此這里的條件判斷為 false,但是當(dāng)我們通過泛型來做到同樣的事情時,情況就發(fā)生了變化。

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

當(dāng)我們用泛型傳遞時候,跟預(yù)想中的不太一樣,這里會把泛型傳入的 number 和 string 拆分之后在去運行 extends 判斷。因此最后的結(jié)果是 string | number。

聯(lián)合類型在泛型中的表現(xiàn)是分配之后再傳入。

在實踐中一定要警惕這個小小的差異。我們可以使用如下的方式避免這種先分配再傳入的規(guī)則。

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

never 表示所有類型的子類型,因此也被看成是一個聯(lián)合類型,當(dāng)我們在泛型中傳入 never 時也會同理出現(xiàn)同樣的問題。

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

注意他們的不同。

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

四、定義一個 pick

現(xiàn)有一個對象 A 有很多個屬性,我希望重新定義一個新的對象 B,該對象的屬性是從 A 里挑選出來的,那么 B 的類型應(yīng)該怎么定義呢。

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

當(dāng)然,我們可以用常規(guī)的方式來定義,不過有的時候這樣會比較麻煩。

interface B {
  name: string,
  age: number
}

我們也可以利用泛型和 extends,定義一個 Pick 類型。

type Pick<T, K extends keyof T> = {
  [P in K]: T[P]
}

type B = Pick<A, 'name' | 'age'>

當(dāng)我們在 Pick 中傳入 A 時, keyof A 的結(jié)果為 name | age | gender | class,因此 'name' | 'age' 是 keyof A 的子類型。

此時的 B 得到與上面寫法一樣的結(jié)果。

五、定義一個 Exclude

現(xiàn)在我有一個聯(lián)合類型。

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

我希望排除其中一個 name,得到一個新的聯(lián)合類型。

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

此時我們可以定一個排除的泛型類型來做到這個事情。

type b = Exclude<a, 'name'>

這個 Exclude 是如何實現(xiàn)的呢?非常的簡單。

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

我們來分析一下,首先剛才我們已經(jīng)知道,當(dāng)傳入的泛型為聯(lián)合類型時,會先分配再傳入。

因此,此時傳入的聯(lián)合類型 a 會被拆分傳入。

也就是說,T exnteds U 的比較會變成。

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

所以通過這種方式,我們可以做到從聯(lián)合類型中排除指定的類型。

六、定義一個 Omit

Omit 是 Pick 的取反,表示挑選剩余的屬性組成新的對象。理解了 Pick 和 Exclude,這個理解起來非常容易。

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

使用:

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

type B = Omit<A, 'name'>

等價于:

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

大家可以自己分析一下 Omit 的實現(xiàn)原理,應(yīng)該是沒有任何難度的。

七、最后

最后來個騷的,大家分析一下這玩意兒有什么用

type TypeString<T> =
    T extends string ? "string" :
    T extends number ? "number" :
    T extends boolean ? "boolean" :
    T extends undefined ? "undefined" :
    T extends Function ? "function" :
    "object";
責(zé)任編輯:姜華 來源: 這波能反殺
相關(guān)推薦

2024-01-24 08:31:13

extends?接口規(guī)范

2022-08-19 12:12:02

TypeScriptInfer 類型

2020-06-01 09:40:06

開發(fā)ReactTypeScript

2022-08-19 09:01:59

ReactTS類型

2010-02-07 13:45:12

Android操作系統(tǒng)

2018-11-08 14:39:50

Excel表結(jié)構(gòu)數(shù)據(jù)

2020-09-13 09:16:17

TypeScriptJavaScript開發(fā)

2021-05-08 09:25:52

開發(fā)技能代碼

2021-07-27 06:06:34

TypeScript語言運算符

2015-11-02 09:36:59

Javasuperextends

2021-08-09 11:16:04

監(jiān)控系統(tǒng)架構(gòu)技術(shù)

2024-05-11 10:19:31

TypeScript類型接口

2020-09-23 09:08:05

typescript

2022-04-11 08:42:09

TypeScript子類型定義

2022-08-08 09:00:42

TypeScript映射類型

2021-07-01 15:17:14

MYSQL存儲數(shù)據(jù)庫

2020-03-13 14:45:14

Java枚舉代碼

2016-06-08 13:42:08

2015-03-03 13:54:53

2023-12-28 12:07:21

點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 2019天天干夜夜操 | 国产一区欧美 | 91干b| 欧美日韩免费视频 | 黑人巨大精品欧美一区二区免费 | 日韩a| 视频一区二区在线观看 | 欧美2区 | 欧美一区二区小视频 | 麻豆久久久久久久久久 | 毛片网络 | 在线播放亚洲 | 国产电影一区二区三区爱妃记 | 国内精品视频在线 | 欧美日韩精品免费 | 国产一级大片 | 国产第一页在线播放 | 午夜影院在线观看视频 | 国产精品一区二区三区在线 | 日韩www | 91精品国产欧美一区二区成人 | 成年人网站免费视频 | 国产精品成人一区 | 欧美成人激情视频 | aaaaaa大片免费看最大的 | 中文字幕国产精品视频 | 欧美激情一区二区三区 | 亚洲精品99| 精品免费国产 | 成人依人 | 成人在线观看黄 | 日韩一区二区三区视频 | 久久久久免费观看 | 爱草视频| 国产在线精品一区二区三区 | 一级a性色生活片久久毛片 一级特黄a大片 | 日韩视频免费在线 | 在线观看国产视频 | 精品成人 | 精品视频在线观看 | 免费在线观看成人 |