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

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


咨詢
建站咨詢
