新聞中心
介紹
TypeScript 是 JavaScript 語(yǔ)言的擴(kuò)展,它使用 JavaScript 運(yùn)行時(shí)和編譯時(shí)類型檢查器。

創(chuàng)新互聯(lián)建站是一家專注于網(wǎng)站設(shè)計(jì)制作、成都網(wǎng)站建設(shè)與策劃設(shè)計(jì),白云網(wǎng)站建設(shè)哪家好?創(chuàng)新互聯(lián)建站做網(wǎng)站,專注于網(wǎng)站建設(shè)十載,網(wǎng)設(shè)計(jì)領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:白云等地區(qū)。白云做網(wǎng)站價(jià)格咨詢:028-86922220
TypeScript 提供了多種方法來(lái)表示代碼中的對(duì)象,其中一種是使用接口。TypeScript 中的接口有兩種使用場(chǎng)景:您可以創(chuàng)建類必須遵循的約定,例如,這些類必須實(shí)現(xiàn)的成員,還可以在應(yīng)用程序中表示類型,就像普通的類型聲明一樣。
您可能會(huì)注意到接口和類型共享一組相似的功能。
事實(shí)上,一個(gè)幾乎總是可以替代另一個(gè)。
主要區(qū)別在于接口可能對(duì)同一個(gè)接口有多個(gè)聲明,TypeScript 將合并這些聲明,而類型只能聲明一次。您還可以使用類型來(lái)創(chuàng)建原始類型(例如字符串和布爾值)的別名,這是接口無(wú)法做到的。
TypeScript 中的接口是表示類型結(jié)構(gòu)的強(qiáng)大方法。它們?cè)试S您以類型安全的方式使用這些結(jié)構(gòu)并同時(shí)記錄它們,從而直接改善開(kāi)發(fā)人員體驗(yàn)。
在今天的文章中,我們將在 TypeScript 中創(chuàng)建接口,學(xué)習(xí)如何使用它們,并了解普通類型和接口之間的區(qū)別。
我們將嘗試不同的代碼示例,可以在 TypeScript 環(huán)境或 TypeScript Playground(一個(gè)允許您直接在瀏覽器中編寫(xiě) TypeScript 的在線環(huán)境)中遵循這些示例。
準(zhǔn)備工作
要完成今天的示例,我們將需要做如下準(zhǔn)備工作:
- 一個(gè)環(huán)境。我們可以執(zhí)行 TypeScript 程序以跟隨示例。要在本地計(jì)算機(jī)上進(jìn)行設(shè)置,我們將需要準(zhǔn)備以下內(nèi)容。
- 為了運(yùn)行處理 TypeScript 相關(guān)包的開(kāi)發(fā)環(huán)境,同時(shí)安裝了 Node 和 npm(或 yarn)。本文教程中使用 Node.js 版本 為14.3.0 和 npm 版本 6.14.5 進(jìn)行了測(cè)試。要在 macOS 或 Ubuntu 18.04 上安裝,請(qǐng)按照如何在 macOS 上安裝 Node.js 和創(chuàng)建本地開(kāi)發(fā)環(huán)境或如何在 Ubuntu 18.04 上安裝 Node.js 的使用 PPA 安裝部分中的步驟進(jìn)行操作。如果您使用的是適用于 Linux 的 Windows 子系統(tǒng) (WSL),這也適用。
- 此外,我們需要在機(jī)器上安裝 TypeScript 編譯器 (tsc)。為此,請(qǐng)參閱官方 TypeScript 網(wǎng)站。
- 如果你不想在本地機(jī)器上創(chuàng)建 TypeScript 環(huán)境,你可以使用官方的 TypeScript Playground 來(lái)跟隨。
- 您將需要足夠的 JavaScript 知識(shí),尤其是 ES6+ 語(yǔ)法,例如解構(gòu)、rest 運(yùn)算符和導(dǎo)入/導(dǎo)出。如果您需要有關(guān)這些主題的更多信息,建議閱讀我們的如何用 JavaScript 編寫(xiě)代碼系列。
- 本文教程將參考支持 TypeScript 并顯示內(nèi)聯(lián)錯(cuò)誤的文本編輯器的各個(gè)方面。這不是使用 TypeScript 所必需的,但確實(shí)可以更多地利用 TypeScript 功能。為了獲得這些好處,您可以使用像 Visual Studio Code 這樣的文本編輯器,它完全支持開(kāi)箱即用的 TypeScript。你也可以在 TypeScript Playground 中嘗試這些好處。
本教程中顯示的所有示例都是使用 TypeScript 4.2.2 版創(chuàng)建的。
在 TypeScript 中創(chuàng)建和使用接口
在本節(jié)中,我們將使用 TypeScript 中可用的不同功能創(chuàng)建接口,您還將學(xué)習(xí)如何使用您創(chuàng)建的接口。
TypeScript 中的接口是通過(guò)使用 interface 關(guān)鍵字后跟接口名稱,然后是帶有接口主體的 {} 塊來(lái)創(chuàng)建的。例如,這里是一個(gè) Logger 接口:
interface Logger {
log: (message: string) => void;
}
與使用類型聲明創(chuàng)建普通類型類似,我們可以在 {} 中指定類型的字段及其類型:
interface Logger {
log: (message: string) => void;
}
Logger 接口表示一個(gè)對(duì)象,該對(duì)象具有一個(gè)名為 log 的屬性。此屬性是一個(gè)接受字符串類型的單個(gè)參數(shù)并返回 void 的函數(shù)。
我們可以將 Logger 接口用作任何其他類型。下面是一個(gè)創(chuàng)建與 Logger 接口匹配的對(duì)象字面量的示例:
interface Logger {
log: (message: string) => void;
}
const logger: Logger = {
log: (message) => console.log(message),
};
使用 Logger 接口作為其類型的值必須具有與 Logger 接口聲明中指定的成員相同的成員。如果某些成員是可選的,則可以省略它們。
由于值必須遵循接口中聲明的內(nèi)容,因此,添加無(wú)關(guān)字段將導(dǎo)致編譯錯(cuò)誤。例如,在對(duì)象字面量中,嘗試添加接口中缺少的新屬性:
interface Logger {
log: (message: string) => void;
}
const logger: Logger = {
log: (message) => console.log(message),
otherProp: true,
};
在這種情況下,TypeScript 編譯器會(huì)發(fā)出錯(cuò)誤 2322,因?yàn)?Logger 接口聲明中不存在此屬性:
Output
Type '{ log: (message: string) => void; otherProp: boolean; }' is not assignable to type 'Logger'.
Object literal may only specify known properties, and 'otherProp' does not exist in type 'Logger'. (2322)
與使用普通類型聲明類似,可以通過(guò)附加 ? 將屬性轉(zhuǎn)換為可選屬性。以他們的名義。
擴(kuò)展其他類型
創(chuàng)建接口時(shí),我們可以從不同的對(duì)象類型進(jìn)行擴(kuò)展,允許您的接口包含來(lái)自擴(kuò)展類型的所有類型信息。這使您能夠編寫(xiě)具有一組通用字段的小型接口,并將它們用作構(gòu)建塊來(lái)創(chuàng)建新接口。
想象一下,我們?nèi)绻幸粋€(gè) Clearable 接口,比如這個(gè):
interface Clearable {
clear: () => void;
}
然后,我們可以創(chuàng)建一個(gè)從它擴(kuò)展的新接口,繼承它的所有字段。在以下示例中,接口 Logger 是從 Clearable 接口擴(kuò)展而來(lái)的。注意突出顯示的行:
?
xxxxxxxxxx
1
interface Clearable {2
clear: () => void;
3
}
4
interface Loggerextends Clearable{5
log: (message: string) => void;
6
}
7
?
Logger 接口現(xiàn)在還有一個(gè) clear 成員,它是一個(gè)不接受參數(shù)并返回 void 的函數(shù)。這個(gè)新成員繼承自 Clearable 接口。就像我們這樣做一樣:
?
xxxxxxxxxx
1
interface Logger {2
log: (message: string) => void;
3
clear: () => void;
4
}
5
?
當(dāng)使用一組通用字段編寫(xiě)大量接口時(shí),我們可以將它們提取到不同的接口并更改接口以擴(kuò)展創(chuàng)建的新接口。
回到前面使用的 Clearable 示例,假設(shè)我們的應(yīng)用程序需要一個(gè)不同的接口,例如下面的 StringList 接口,來(lái)表示一個(gè)包含多個(gè)字符串的數(shù)據(jù)結(jié)構(gòu):
interface StringList {
push: (value: string) => void;
get: () => string[];
}
通過(guò)使這個(gè)新的 StringList 接口擴(kuò)展現(xiàn)有的 Clearable 接口,指定該接口還具有在 Clearable 接口中設(shè)置的成員,將 clear 屬性添加到 StringList 接口的類型定義中:
interface StringList extends Clearable {
push: (value: string) => void;
get: () => string[];
}
接口可以從任何對(duì)象類型擴(kuò)展,例如接口、普通類型,甚至是類。
帶有可調(diào)用簽名的接口
如果接口也是可調(diào)用的(也就是說(shuō),它也是一個(gè)函數(shù)),我們可以通過(guò)創(chuàng)建可調(diào)用簽名在接口聲明中傳達(dá)該信息。
通過(guò)在未綁定到任何成員的接口內(nèi)添加函數(shù)聲明并在設(shè)置函數(shù)的返回類型時(shí)使用 : 而不是 => 來(lái)創(chuàng)建可調(diào)用簽名。
例如,在 Logger 界面中添加一個(gè)可調(diào)用的簽名,如下面突出顯示的代碼所示:
interface Logger {
(message: string): void;
log: (message: string) => void;
}
請(qǐng)注意,可調(diào)用簽名類似于匿名函數(shù)的類型聲明,但在返回類型中,我們使用的是 : 而不是 =>。這意味著綁定到 Logger 接口類型的任何值都可以作為函數(shù)直接調(diào)用。
要?jiǎng)?chuàng)建與Logger 接口匹配的值,我們需要考慮接口的要求:
- 它必須是可調(diào)用的。
- 它必須有一個(gè)名為 log 的屬性,該屬性是一個(gè)接受單個(gè)字符串參數(shù)的函數(shù)。
讓我們創(chuàng)建一個(gè)名為 logger 的變量,它可以分配給 Logger 接口的類型:
interface Logger {
(message: string): void;
log: (message: string) => void;
}
const logger: Logger = (message: string) => {
console.log(message);
}
logger.log = (message: string) => {
console.log(message);
}
要匹配 Logger 接口,該值必須是可調(diào)用的,這就是我們將 logger 變量分配給函數(shù)的原因:
interface Logger {
(message: string): void;
log: (message: string) => void;
}
const logger: Logger = (message: string) => {
console.log(message);
}
logger.log = (message: string) => {
console.log(message);
}
然后,我們將 log 屬性添加到 logger 函數(shù):
interface Logger {
(message: string): void;
log: (message: string) => void;
}
const logger: Logger = (message: string) => {
console.log(message);
}
logger.log = (message: string) => {
console.log(message);
}
這是 Logger 接口所要求的。綁定到 Logger 接口的值還必須具有 log 屬性,該屬性是一個(gè)接受單個(gè)字符串參數(shù)并返回 void 的函數(shù)。
如果我們沒(méi)有包含 log 屬性,TypeScript Compiler 會(huì)給你錯(cuò)誤 2741:
Output
Property 'log' is missing in type '(message: string) => void' but required in type 'Logger'. (2741)
如果 logger 變量中的 log 屬性具有不兼容的類型簽名,TypeScript 編譯器將發(fā)出類似的錯(cuò)誤,例如將其設(shè)置為 true:
interface Logger {
(message: string): void;
log: (message: string) => void;
}
const logger: Logger = (message: string) => {
console.log(message);
}
logger.log = true;
在這種情況下,TypeScript 編譯器會(huì)顯示錯(cuò)誤 2322:
Output
Type 'boolean' is not assignable to type '(message: string) => void'. (2322)
將變量設(shè)置為具有特定類型的一個(gè)很好的功能,在這種情況下,將記錄器變量設(shè)置為具有記錄器接口的類型,TypeScript 現(xiàn)在可以推斷記錄器函數(shù)和日志中函數(shù)的參數(shù)類型 財(cái)產(chǎn)。
我們可以通過(guò)從兩個(gè)函數(shù)的參數(shù)中刪除類型信息來(lái)檢查。請(qǐng)注意,在下面突出顯示的代碼中,消息參數(shù)沒(méi)有類型:
interface Logger {
(message: string): void;
log: (message: string) => void;
}
const logger: Logger = (message)=> {
console.log(message);
}
logger.log = (message)=> {
console.log(message);
}
在這兩種情況下,編輯器應(yīng)該仍然能夠顯示參數(shù)的類型是字符串,因?yàn)檫@是 Logger 接口所期望的類型。
帶有索引簽名的接口
可以向界面添加索引簽名,就像使用普通類型一樣,從而允許界面具有無(wú)限數(shù)量的屬性。
例如,如果想創(chuàng)建一個(gè)具有無(wú)限數(shù)量的字符串字段的 DataRecord 接口,可以使用以下突出顯示的索引簽名:
interface DataRecord {
[key: string]: string;
}
然后,我們可以使用 DataRecord 接口設(shè)置具有多個(gè)字符串類型參數(shù)的任何對(duì)象的類型:
interface DataRecord {
[key: string]: string;
}
const data: DataRecord = {
fieldA: "valueA",
fieldB: "valueB",
fieldC: "valueC",
// ...
};
在本文中,我們使用 TypeScript 中可用的不同功能創(chuàng)建了接口,并學(xué)習(xí)了如何使用您創(chuàng)建的接口。
在接下來(lái)的內(nèi)容中,我們將了解更多關(guān)于類型和接口聲明之間的區(qū)別,并獲得聲明合并和模塊擴(kuò)充的實(shí)踐。
類型和接口的區(qū)別
到目前為止,我們已經(jīng)看到接口聲明和類型聲明是相似的,具有幾乎相同的特性集。
例如,我們創(chuàng)建了一個(gè)從 Clearable 接口擴(kuò)展而來(lái)的 Logger 接口:
interface Clearable {
clear: () => void;
}
interface Logger extends Clearable {
log: (message: string) => void;
}
可以使用兩種類型聲明來(lái)復(fù)制相同的類型表示:
type Clearable = {
clear: () => void;
}
type Logger = Clearable & {
log: (message: string) => void;
}
如前面內(nèi)容所示,接口聲明可用于表示各種對(duì)象,從函數(shù)到具有無(wú)限數(shù)量屬性的復(fù)雜對(duì)象。這也適用于類型聲明,甚至從其他類型擴(kuò)展,因?yàn)椋覀兛梢允褂媒患\(yùn)算符 & 將多個(gè)類型相交。
由于類型聲明和接口聲明非常相似,因此,需要考慮各自獨(dú)有的特定功能,并在代碼庫(kù)中保持一致。選擇一種在代碼庫(kù)中創(chuàng)建類型表示,并且僅在需要僅對(duì)它可用的特定功能時(shí)才使用另一種。
例如,類型聲明具有接口聲明所缺乏的一些特性,例如:
- 聯(lián)合類型。
- 映射類型。
- 原始類型的別名。
僅可用于接口聲明的功能之一是聲明合并,我們將在接下來(lái)的內(nèi)容中學(xué)習(xí)它。重要的是要注意,如果您正在編寫(xiě)一個(gè)庫(kù)并希望為庫(kù)用戶提供擴(kuò)展庫(kù)提供的類型的能力,那么聲明合并可能很有用,因?yàn)轭愋吐暶鳠o(wú)法做到這一點(diǎn)。
聲明合并
TypeScript 可以將多個(gè)聲明合并為一個(gè)聲明,使他們能夠?yàn)橥粋€(gè)數(shù)據(jù)結(jié)構(gòu)編寫(xiě)多個(gè)聲明,并在編譯期間將它們捆綁在一起,就像它們是一個(gè)單一類型一樣。
在文中,我們將看到它是如何工作的,以及為什么它在使用接口時(shí)很有幫助。
TypeScript 中的接口可以重新打開(kāi);也就是說(shuō),可以合并同一接口的多個(gè)聲明。當(dāng)我們想要將新字段添加到現(xiàn)有界面時(shí),這很有用。
例如,假設(shè)我們有一個(gè)名為 DatabaseOptions 的接口,如下所示:
interface DatabaseOptions {
host: string;
port: number;
user: string;
password: string;
}
此接口將用于在連接到數(shù)據(jù)庫(kù)時(shí)傳遞選項(xiàng)。
稍后在代碼中,聲明一個(gè)具有相同名稱但具有一個(gè)名為 dsnUrl 的字符串字段的接口,如下所示
interface DatabaseOptions {
dsnUrl: string;
}
當(dāng) TypeScript 編譯器開(kāi)始讀取我們的代碼時(shí),它會(huì)將 DatabaseOptions 接口的所有聲明合并為一個(gè)。從 TypeScript 編譯器的角度來(lái)看,DatabaseOptions 現(xiàn)在是:
interface DatabaseOptions {
host: string;
port: number;
user: string;
password: string;
dsnUrl: string;
}
該接口包括我們最初聲明的所有字段,以及我們單獨(dú)聲明的新字段 dsnUrl。兩個(gè)聲明已合并。
模塊擴(kuò)充
當(dāng)我們需要使用新屬性擴(kuò)充現(xiàn)有模塊時(shí),聲明合并很有幫助。一個(gè)用例是,當(dāng)我們向庫(kù)提供的數(shù)據(jù)結(jié)構(gòu)添加更多字段時(shí)。這在名為 express 的 Node.js 庫(kù)中相對(duì)常見(jiàn),它允許我們創(chuàng)建 HTTP 服務(wù)器。
使用 express 時(shí),一個(gè) Request 和一個(gè) Response 對(duì)象被傳遞給我們的請(qǐng)求處理程序(負(fù)責(zé)為 HTTP 請(qǐng)求提供響應(yīng)的函數(shù))。Request 對(duì)象通常用于存儲(chǔ)特定于特定請(qǐng)求的數(shù)據(jù)。例如,我們可以使用它來(lái)存儲(chǔ)發(fā)出初始 HTTP 請(qǐng)求的登錄用戶:
const myRoute = (req: Request, res: Response) => {
res.json({ user: req.user});
}
在這里,請(qǐng)求處理程序?qū)⒂脩糇侄卧O(shè)置為登錄用戶的 json 發(fā)送回客戶端。使用負(fù)責(zé)用戶身份驗(yàn)證的快速中間件,將登錄的用戶添加到代碼中另一個(gè)位置的請(qǐng)求對(duì)象。
Request 接口本身的類型定義沒(méi)有用戶字段,因此上面的代碼會(huì)給出類型錯(cuò)誤 2339:
Property 'user' does not exist on type 'Request'. (2339)
要解決這個(gè)問(wèn)題,我們必須為 express 包創(chuàng)建一個(gè)模塊擴(kuò)充,利用聲明合并向請(qǐng)求接口添加一個(gè)新屬性。
如果我們?cè)?express 類型聲明中檢查 Request 對(duì)象的類型,我們會(huì)注意到它是一個(gè)添加在名為 Express 的全局命名空間中的接口,如 DefinitiveTyped 存儲(chǔ)庫(kù)中的文檔所示:
declare global {
namespace Express {
// These open interfaces may be extended in an application-specific manner via declaration merging.
// See for example method-override.d.ts (https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/method-override/index.d.ts)
interface Request {}
interface Response {}
interface Application {}
}
}
注意:類型聲明文件是只包含類型信息的文件。DefinitiveTyped 存儲(chǔ)庫(kù)是為沒(méi)有類型聲明的包提交類型聲明的官方存儲(chǔ)庫(kù)。npm 上可用的 @types/
要使用模塊擴(kuò)充向 Request 接口添加新屬性,我們必須在本地類型聲明文件中復(fù)制相同的結(jié)構(gòu)。例如,假設(shè)我們創(chuàng)建了一個(gè)名為 express.d.ts 的文件,如下所示,然后將其添加到 tsconfig.json 的 types 選項(xiàng)中:
import 'express';
declare global {
namespace Express {
interface Request {
user: {
name: string;
}
}
}
}
從 TypeScript 編譯器的角度來(lái)看,Request 接口有一個(gè)用戶屬性,它們的類型設(shè)置為一個(gè)對(duì)象,該對(duì)象具有一個(gè)稱為字符串類型名稱的屬性。發(fā)生這種情況是因?yàn)橥唤涌诘乃新暶鞫急缓喜⒘恕?
假設(shè)我們正在創(chuàng)建一個(gè)庫(kù),并希望為我們的庫(kù)的用戶提供增加自己的庫(kù)提供的類型的選項(xiàng),就像我們?cè)谏厦媸褂?express 所做的那樣。在這種情況下,我們需要從庫(kù)中導(dǎo)出接口,因?yàn)槠胀愋吐暶鞑恢С帜K擴(kuò)充。
結(jié)論
到這里,在本文提供的教程就結(jié)束了。
我們編寫(xiě)了多個(gè) TypeScript 接口來(lái)表示各種數(shù)據(jù)結(jié)構(gòu),發(fā)現(xiàn)了如何將不同的接口一起用作構(gòu)建塊來(lái)創(chuàng)建強(qiáng)大的類型,并了解了普通類型聲明和接口之間的區(qū)別。
我們現(xiàn)在可以開(kāi)始為代碼庫(kù)中的數(shù)據(jù)結(jié)構(gòu)編寫(xiě)接口,讓我們擁有類型安全的代碼和文檔。
新聞名稱:如何在TypeScript中使用接口
本文路徑:http://www.5511xx.com/article/dhddhhp.html


咨詢
建站咨詢
