extends
是 typeScript 中的關鍵字。在 typeScript 的類型編程世界里面,它所扮演的角色實在是太重要了,所以,我們不得不需要重視它,深入學習它。在我看來,掌握它就是進入高級 typeScript 類型編程世界的敲門磚。但是,現(xiàn)實是,它在不同的上下文中,具體不同的,相差很大的語義。如果沒有深入地對此進行梳理,它會給開發(fā)者帶來很大的困惑。梳理并深入學習它,最后掌握它,這就是我編寫這篇文章的初衷。
extends 的幾個語義
讓我們開門見山地說吧,在 typeScript 在不同的上下文中,extends
有以下幾個語義。不同語義即有不同的用途:
- 用于表達類型組合;
- 用于表達面向對象中「類」的繼承
- 用于表達泛型的類型約束;
- 在條件類型(conditional type)中,充當類型表達式,用于求值。
extends 與 類型組合/類繼承
extends
可以跟 interface
結合起來使用,用于表達類型組合。
示例 1-1
interface ChildComponentProps { onChange: (val: string)=> void } interface ParentComponentProps extends ChildComponentProps { value: string }
在 react 組件化開發(fā)模式中,存在一種自底向上的構建模式 – 我們往往會先把所有最底層的子組件的 props
構建好,最后才定義 container component
(負責提升公共 state,聚合和分發(fā) props) 的 props
。此時,inferface 的 extends
正好能表達這種語義需求 – 類型的組合(將所有子組件的 props
聚合到一塊)。
當然,interface
的 extends
從句是可以跟著多個組合對象,多個組合對象之間用逗號,
隔開。比如ParentComponentProps
組合多個子組件的 props
:
示例 1-2
interface ChildComponentProps { onChange: (val: string)=> void } interface ChildComponentProps2 { onReset: (value: string)=> void } interface ParentComponentProps extends ChildComponentProps, ChildComponentProps2 { value: string }
注意,上面指出的是「多個組合對象」,這里也包括了Class
。對,就是普通面向概念中的「類」。也就是說,下面的代碼也是合法的:
示例 1-3
interface ChildComponentProps { onChange: (val: string)=> void } interface ChildComponentProps2 { onReset: (value: string)=> void } class SomeClass { private name!: string // 變量聲明時,變量名跟著一個感嘆號`!`,這是「賦值斷言」的語法 updateName(name:string){ this.name = name || '' } } interface ParentComponentProps extends ChildComponentProps, ChildComponentProps2, SomeClass { value: string }
之所以這也是合法的,一切源于一個特性:在 typeScript 中,一個 class 變量既是「值」也是「類型」。在interface extends class
的上下文中,顯然是取 class 是「類型」的語義。一個 interface extends
另外一個 class,可以理解為 interface 拋棄這個 class 的所有實現(xiàn)代碼,只是跟這個 class 的「類型 shape」 進行組合。還是上面的示例代碼中,從類型 shape 的角度,SomeClass
就等同于下面的 interface:
示例 1-4
interface SomeClass { name: string updateName: (name:string)=> void }
好了,