TypeScript 中 Interface 與 Type 的區(qū)別?該用哪個(gè)比較好?
回復(fù)交流,加入前端編程面試算法每日一題群

接口 與 類型別名 的異同點(diǎn)
相同點(diǎn)
1. 都可以描述對象或函數(shù)
// 接口
interface Sister {
name: string;
age: number;
}
interface SetSister {
(name: string, age: number): void;
}
// 類型別名
type Sister = {
name: string;
age: number;
};
type SetSister = (name: string, age: number) => void;
2. 都可以擴(kuò)展
interface 和 type 可以混合擴(kuò)展,也就是說 interface 可以擴(kuò)展 type,type 也可以擴(kuò)展 interface。
但需要注意的是,接口的擴(kuò)展是繼承( extends )。類型別名的擴(kuò)展就是交叉類型(通過 & 實(shí)現(xiàn))
// 接口
interface SisterAn {
name: string;
}
// 類型別名
type SisterRan = {
age: number;
}
// 接口擴(kuò)展接口
interface Sister extends SisterAn {
age: number;
}
// 類型別名擴(kuò)展類型別名
type SisterPro = SisterRan & {
name: string;
}
// 接口擴(kuò)展類型別名
interface Sister extends SisterRan {
name: string;
}
// 類型別名擴(kuò)展接口
type SisterPro = SisterAn & {
age: number;
}
區(qū)別
官方 中這樣介紹兩者的區(qū)別:
Type aliases and interfaces are very similar, and in many cases you can choose between them freely. Almost all features of an
interfaceare available intype, the key distinction is that a type cannot be re-opened to add new properties vs an interface which is always extendable.
意思就是說幾乎接口的所有特性都可以通過類型別名來實(shí)現(xiàn),主要區(qū)別在于:
1. 不同的聲明范圍
與接口不同,可以為任意的類型創(chuàng)建類型別名
類型別名的右邊可以是任何類型,包括基本類型、元祖、類型表達(dá)式( & 或 | 等);而在接口聲明中,右邊必須為變量結(jié)構(gòu)。例如,下面的類型別名就不能轉(zhuǎn)換成接口
type Name = string
type Text = string | { text: string };
type Coordinates = [number, number];
2. 不同的擴(kuò)展形式
接口是通過繼承的方式來擴(kuò)展,類型別名是通過 & 來擴(kuò)展
// 接口擴(kuò)展
interface SisterAn {
name: string;
}
interface Sister extends SisterAn {
age: number;
}
// 類型別名擴(kuò)展
type SisterRan = {
age: number;
}
type SisterPro = SisterRan & {
name: string;
}
這里需要注意的是,接口擴(kuò)展時(shí),typescript 會(huì)檢查擴(kuò)展的接口是否可以賦值給被擴(kuò)展的接口
// 接口擴(kuò)展
interface SisterAn {
name: string;
age: string
}
interface Sister extends SisterAn {
name: string;
age: number;
}
// 報(bào)錯(cuò):
// Interface 'Sister' incorrectly extends interface 'SisterAn'.
// Types of property 'age' are incompatible.
// Type 'number' is not assignable to type 'string'
但使用交集類型時(shí)就不會(huì)出現(xiàn)這種情況
// 類型別名擴(kuò)展
type SisterRan = {
name: string;
age: string;
}
type SisterPro = SisterRan & {
name: string;
age: number;
}
類型別名擴(kuò)展時(shí),typescript 將盡其所能把擴(kuò)展和被擴(kuò)展的類型組合在一起,而不會(huì)拋出編譯時(shí)錯(cuò)誤
3. 不同的重復(fù)定義表現(xiàn)形式
接口可以定義多次,多次的聲明會(huì)自動(dòng)合并
interface Sister {
name: string;
}
interface Sister {
age: number;
}
const sisterAn: Sister = {
name: 'sisterAn'
}
// 報(bào)錯(cuò):Property 'age' is missing in type '{ name: string; }' but required in type 'Sister'
const sisterRan: Sister = {
name: 'sisterRan',
age: 12
}
// 正確
但是類型別名如果定義多次,會(huì)報(bào)錯(cuò)
type Sister = { // Duplicate identifier 'Sister'
name: string;
}
type Sister = { // Duplicate identifier 'Sister'
age: number;
}
如何選擇 Interface 、 Type
雖然 官方 中說幾乎接口的所有特性都可以通過類型別名來實(shí)現(xiàn),但建議優(yōu)先選擇接口,接口滿足不了再使用類型別名,在 typescript 官網(wǎng) Preferring Interfaces Over Intersections 有說明,具體內(nèi)容如下:
大多數(shù)時(shí)候,對象類型的簡單類型別名的作用與接口非常相似
interface Foo { prop: string }
type Bar = { prop: string };但是,一旦你需要組合兩個(gè)或多個(gè)類型來實(shí)現(xiàn)其他類型時(shí),你就可以選擇使用接口擴(kuò)展這些類型,或者使用類型別名將它們交叉在一個(gè)中(交叉類型),這就是差異開始的時(shí)候。
接口創(chuàng)建一個(gè)單一的平面對象類型來檢測屬性沖突,這通常很重要! 而交叉類型只是遞歸的進(jìn)行屬性合并,在某種情況下可能產(chǎn)生 never類型接口也始終顯示得更好,而交叉類型做為其他交叉類型的一部分時(shí),直觀上表現(xiàn)不出來,還是會(huì)認(rèn)為是不同基本類型的組合。 接口之間的類型關(guān)系會(huì)被緩存,而交叉類型會(huì)被看成組合起來的一個(gè)整體。 最后一個(gè)值得注意的區(qū)別是,在檢查到目標(biāo)類型之前會(huì)先檢查每一個(gè)組分。 出于這個(gè)原因,建議使用接口/擴(kuò)展擴(kuò)展類型而不是創(chuàng)建交叉類型。
- type Foo = Bar & Baz & {
- someProp: string;
- }
+ interface Foo extends Bar, Baz {
+ someProp: string;
+ }
簡單的說,接口更加符合 JavaScript 對象的工作方式,簡單的說明下,當(dāng)出現(xiàn)屬性沖突時(shí):
// 接口擴(kuò)展
interface Sister {
sex: number;
}
interface SisterAn extends Sister {
sex: string;
}
// index.ts(5,11): error TS2430: Interface 'SisterAn' incorrectly extends interface 'Sister'.
// Types of property 'sex' are incompatible.
// Type 'string' is not assignable to type 'number'.
// 交叉類型
type Sister1 = {
sex: number;
}
type Sister2 = {
sex: string;
}
type SisterAn = Sister1 & Sister2;
// 不報(bào)錯(cuò),此時(shí)的 SisterAn 是一個(gè)'number & string'類型,也就是 never
來源:https://github.com/Advanced-Frontend/Daily-Interview-Question
最后
號內(nèi)回復(fù):
120 套模版