詳解TypeScript中type與interface的區(qū)別
類(lèi)型別名 type
首先認(rèn)識(shí)一下什么是類(lèi)型別名?
類(lèi)型別名用來(lái)給一個(gè)類(lèi)型起個(gè)新名字,使用 type 創(chuàng)建類(lèi)型別名,類(lèi)型別名不僅可以用來(lái)表示基本類(lèi)型,還可以用來(lái)表示對(duì)象類(lèi)型、聯(lián)合類(lèi)型、元組和交集。讓我們看一些例子:
type userName = string; // 基本類(lèi)型
type userId = string | number; // 聯(lián)合類(lèi)型
type arr = number[];
// 對(duì)象類(lèi)型
type Person = {
id: userId; // 可以使用定義類(lèi)型
name: userName;
age: number;
gender: string;
isWebDev: boolean;
};
// 范型
type Tree<T> = { value: T };
const user: Person = {
id: "901",
name: "椿",
age: 22,
gender: "女",
isWebDev: false,
};
const numbers: arr = [1, 8, 9];接口 interface
接口是命名數(shù)據(jù)結(jié)構(gòu)(例如對(duì)象)的另一種方式;與type 不同,interface僅限于描述對(duì)象類(lèi)型。
接口的聲明語(yǔ)法也不同于類(lèi)型別名的聲明語(yǔ)法。讓我們將上面的類(lèi)型別名 Person 重寫(xiě)為接口聲明:
interface Person {
id: userId;
name: userName;
age: number;
gender: string;
isWebDev: boolean;
}interface和type的相似之處
在討論二者區(qū)別之前, 首先看一下二者的相似之處(為何開(kāi)發(fā)中,我們覺(jué)得用哪個(gè)都一樣)
都可以描述 Object和Function
兩者都可以用來(lái)描述對(duì)象或函數(shù),但語(yǔ)法不同:
Type
type Point = {
x: number;
y: number;
};
type SetPoint = (x: number, y: number) => void;Interface
interface Point {
x: number;
y: number;
}
interface SetPoint {
(x: number, y: number): void;
}二者都可以被繼承
interface 和 type 都可以繼承。
另一個(gè)值得注意的是,接口和類(lèi)型別名并不互斥。類(lèi)型別名可以繼承接口,反之亦然。只是在實(shí)現(xiàn)形式上,稍微有些差別。
interface 繼承 interface
interface Person{
name:string
}
interface Student extends Person { stuNo: number }interface 繼承 type
type Person{
name:string
}
interface Student extends Person { stuNo: number }type 繼承 type
type Person{
name:string
}
type Student = Person & { stuNo: number }type 繼承 interface
interface Person{
name:string
}
type Student = Person & { stuNo: number }實(shí)現(xiàn) implements
類(lèi)可以實(shí)現(xiàn)interface 以及 type(除聯(lián)合類(lèi)型外)
interface ICat{
setName(name:string): void;
}
class Cat implements ICat{
setName(name:string):void{
// todo
}
}
// type
type ICat = {
setName(name:string): void;
}
class Cat implements ICat{
setName(name:string):void{
// todo
}
}上面提到了特殊情況,類(lèi)無(wú)法實(shí)現(xiàn)聯(lián)合類(lèi)型, 是什么意思呢?
type Person = { name: string; } | { setName(name:string): void };
// 無(wú)法對(duì)聯(lián)合類(lèi)型Person進(jìn)行實(shí)現(xiàn)
// error: A class can only implement an object type or intersection of object types with statically known members.
class Student implements Person {
name= "張三";
setName(name:string):void{
// todo
}
}上面聊了interface與 type的相似之處, 接下來(lái)就來(lái)看看他們的區(qū)別。
二者區(qū)別
1. 定義基本類(lèi)型別名
type可以定義基本類(lèi)型別名, 但是interface無(wú)法定義,如:
type userName = string type stuNo = number ...
2. 聲明聯(lián)合類(lèi)型
type可以聲明聯(lián)合類(lèi)型, 例如:
type Student = {stuNo: number} | {classId: number}3. 聲明元組
type可以聲明 元組類(lèi)型:
type Data = [number, string];
以上都是 type能做到, 而interface做不到的, 接下來(lái)聊聊type做不到的
4. 聲明合并
如果你多次聲明一個(gè)同名的接口,TypeScript 會(huì)將它們合并到一個(gè)聲明中,并將它們視為一個(gè)接口。這稱(chēng)為聲明合并, 例如:
interface Person { name: string }
interface Person { age: number }
let user: Person = {
name: "Tolu",
age: 0,
};這種情況下,如果是type的話,重復(fù)使用Person是會(huì)報(bào)錯(cuò)的:
type Person { name: string };
// Error: 標(biāo)識(shí)符“Person”重復(fù)。ts(2300)
type Person { age: number }5. 索引簽名問(wèn)題
如果你經(jīng)常使用TypeScript, 一定遇到過(guò)相似的錯(cuò)誤:
Type 'xxx' is not assignable to type 'yyy'
Index signature is missing in type 'xxx'.
看個(gè)例子來(lái)理解問(wèn)題:
interface propType{
[key: string] : string
}
let props: propType
type dataType = {
title: string
}
interface dataType1 {
title: string
}
const data: dataType = {title: "訂單頁(yè)面"}
const data1: dataType1 = {title: "訂單頁(yè)面"}
props = data
// Error:類(lèi)型“dataType1”不可分配給類(lèi)型“propType”; 類(lèi)型“dataType1”中缺少索引簽名
props = data1我們發(fā)現(xiàn)dataType和dataType1對(duì)應(yīng)的類(lèi)型一樣,但是interface定義的就賦值失敗,是什么原因呢?剛開(kāi)始百思不解,最后我在 stack overflow上找到了一個(gè)相似的問(wèn)題:

并且很幸運(yùn)的找到了有效的答案:

翻譯過(guò)來(lái)的大致意思就是:
Record<string,string>與{[key:string]:string}相同。只有當(dāng)該類(lèi)型的所有屬性都已知并且可以對(duì)照該索引簽名進(jìn)行檢查時(shí),才允許將子集分配給該索引簽名類(lèi)型。在您的例子中,從exampleType到Record<string,string>的所有內(nèi)容都是可分配的。這只能針對(duì)對(duì)象字面量類(lèi)型進(jìn)行檢查,因?yàn)橐坏┞暶髁藢?duì)象字面量類(lèi)型,就無(wú)法更改它們。因此,索引簽名是已知的。
相反,在你使用interface去聲明變量時(shí),它們?cè)谀且豢填?lèi)型并不是最終的類(lèi)型。由于interfac可以進(jìn)行聲明合并,所以總有可能將新成員添加到同一個(gè)interface定義的類(lèi)型上。
再結(jié)合:point_up_2:第4點(diǎn) 聲明合并的講解, 這樣就很好理解了。就是說(shuō)interface定義的類(lèi)型是不確定的, 后面再來(lái)一個(gè):
interface propType{
title:number
}這樣propType類(lèi)型就被改變了。
總結(jié)
官方推薦用 interface,其他無(wú)法滿足需求的情況下用 type。
但其實(shí),因?yàn)?聯(lián)合類(lèi)型 和 交叉類(lèi)型 是很常用的,所以避免不了大量使用 type 的場(chǎng)景,一些復(fù)雜類(lèi)型也需要通過(guò)組裝后形成類(lèi)型別名來(lái)使用。
所以,如果想保持代碼統(tǒng)一,還是可選擇使用 type。通過(guò)上面的對(duì)比,類(lèi)型別名 其實(shí)可涵蓋 interface 的大部分場(chǎng)景。
對(duì)于 React 組件中 props及 state,使用 type ,這樣能夠保證使用組件的地方不能隨意在上面添加屬性。如果有自定義需求,可通過(guò) HOC二次封裝。
編寫(xiě)三方庫(kù)時(shí)使用interface,其更加靈活自動(dòng)的類(lèi)型合并可應(yīng)對(duì)未知的復(fù)雜使用場(chǎng)景。
以上就是詳解TypeScript中type與interface的區(qū)別的詳細(xì)內(nèi)容,更多關(guān)于TypeScript type interface區(qū)別的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
layui中的tab控件點(diǎn)擊切換觸發(fā)事件
這篇文章主要介紹了layui中的tab控件點(diǎn)擊切換觸發(fā)事件,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06
用javascript作一個(gè)通用向?qū)дf(shuō)明
向?qū)Э梢宰屇愕木W(wǎng)站用戶快速上手使用你的web應(yīng)用,提高網(wǎng)站的吸引力。向?qū)б话惴譃楹脦讉€(gè)步驟,每個(gè)步驟收集一些數(shù)據(jù),并且支持退回功能,所有步驟完成后可以得到每一步的收集結(jié)果。這里給大家展示一種比較通用,靈活且簡(jiǎn)單的向?qū)Э蚣堋?/div> 2011-08-08
JavaScript在圖片繪制文字兩種方法的實(shí)現(xiàn)與對(duì)比
這篇文章主要為大家詳細(xì)介紹了前端實(shí)現(xiàn)在圖片上繪制文字的兩種思路,支持即粘即貼即用,文中的示例代碼講解詳細(xì),需要的小伙伴可以了解下2024-03-03
釘釘小程序web-view內(nèi)嵌H5頁(yè)面并實(shí)現(xiàn)通信
本文主要介紹了釘釘小程序web-view內(nèi)嵌H5頁(yè)面并實(shí)現(xiàn)通信,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05
微信小程序 列表的上拉加載和下拉刷新的實(shí)現(xiàn)
本文主要介紹了微信小程序中實(shí)現(xiàn)列表的上拉加載和下拉刷新的方法。具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧2017-04-04最新評(píng)論

