1. 如何在 TypeScript 中使用函數(shù)

        共 14150字,需瀏覽 29分鐘

         ·

        2022-03-17 11:07

        點(diǎn)擊上方?前端Q,關(guān)注公眾號(hào)

        回復(fù)加群,加入前端Q技術(shù)交流群


        英文 | https://www.digitalocean.com/community/tutorials/how-to-use-functions-in-typescript

        翻譯 | 楊小愛


        介紹
        創(chuàng)建和使用函數(shù)是任何編程語言的基本內(nèi)容,TypeScript 也不例外。TypeScript 完全支持現(xiàn)有的 JavaScript 函數(shù)語法,同時(shí),還添加了類型信息和函數(shù)重載作為新特性。除了為函數(shù)提供額外的文檔外,類型信息還可以減少代碼中出現(xiàn)錯(cuò)誤的機(jī)會(huì),因?yàn)閷o效數(shù)據(jù)類型傳遞給類型安全函數(shù)的風(fēng)險(xiǎn)較低。
        在本教程中,我們將從使用類型信息創(chuàng)建最基本的函數(shù)開始,然后,轉(zhuǎn)到更復(fù)雜的場(chǎng)景,例如,使用剩余參數(shù)和函數(shù)重載。我們將嘗試不同的代碼示例,我們可以在自己的 TypeScript 環(huán)境或 TypeScript Playground(一個(gè)允許我們直接在瀏覽器中編寫 TypeScript 的在線環(huán)境)中遵循這些示例。
        準(zhǔn)備工作
        要完成本教程內(nèi)容,我們需要做如下準(zhǔn)備工作:
        一個(gè)環(huán)境,我們可以在其中執(zhí)行 TypeScript 程序以跟隨示例。要在本地計(jì)算機(jī)上進(jìn)行設(shè)置,我們將需要以下內(nèi)容:
        為了運(yùn)行處理 TypeScript 相關(guān)包的開發(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)建本地開發(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 來跟隨。
        將需要足夠的 JavaScript 知識(shí),尤其是 ES6+ 語法,例如解構(gòu)、rest 運(yùn)算符和導(dǎo)入/導(dǎo)出。如果需要有關(guān)這些主題的更多知識(shí),建議閱讀我們的JavaScript 系列教程。
        本教程將參考支持 TypeScript 并顯示內(nèi)聯(lián)錯(cuò)誤的文本編輯器的各個(gè)方面。這不是使用 TypeScript 所必需的,但確實(shí)可以更多地利用 TypeScript 功能。為了獲得這些好處,我們可以使用像 Visual Studio Code 這樣的文本編輯器,它完全支持開箱即用的 TypeScript。我們也可以在 TypeScript Playground 中嘗試這些好處。
        本教程中顯示的所有示例都是使用 TypeScript 4.2.2 版創(chuàng)建的。
        創(chuàng)建類型化函數(shù)
        在本節(jié)中,我們將在 TypeScript 中創(chuàng)建函數(shù),然后向它們添加類型信息。
        在 JavaScript 中,可以通過多種方式聲明函數(shù)。最流行的一種是使用 function 關(guān)鍵字,如下所示:
        function sum(a, b) {  return a + b;}

        在本例中,sum 是函數(shù)的名稱,(a, b) 是參數(shù),{return a + b;} 是函數(shù)體。

        在 TypeScript 中創(chuàng)建函數(shù)的語法是相同的,除了一個(gè)主要的補(bǔ)充:我們可以讓編譯器知道每個(gè)參數(shù)或參數(shù)應(yīng)該具有什么類型。以下代碼塊顯示了一般語法,突出顯示了類型聲明:

        function functionName(param1: Param1Type, param2: Param2Type): ReturnType {  // ... body of the function}

        使用此語法,我們可以將類型添加到前面顯示的 sum 函數(shù)的參數(shù):

        function sum(a: number, b: number) {  return a + b;}

        這確保 a 和 b 是數(shù)值。

        我們還可以添加返回值的類型:

        function sum(a: number, b: number): number {  return a + b;}

        現(xiàn)在 TypeScript 將期望 sum 函數(shù)返回一個(gè)數(shù)字值。如果我們使用一些參數(shù)調(diào)用函數(shù)并將結(jié)果值存儲(chǔ)在名為 result 的變量中:

        const result = sum(1, 2);

        結(jié)果變量將具有類型編號(hào)。如果我們正在使用 TypeScript 游樂場(chǎng)或使用完全支持 TypeScript 的文本編輯器,將光標(biāo)懸停在 result 上將顯示 const result: number,表明 TypeScript 從函數(shù)聲明中隱含了它的類型。

        如果我們調(diào)用函數(shù)的值的類型與函數(shù)預(yù)期的類型不同,TypeScript 編譯器 (tsc) 會(huì)給我們錯(cuò)誤 2345。對(duì) sum 函數(shù)執(zhí)行以下調(diào)用:

        sum('shark', 'whale');

        這將給出以下內(nèi)容:

        OutputArgument of type 'string' is not assignable to parameter of type 'number'. (2345)

        我們可以在函數(shù)中使用任何類型,而不僅僅是基本類型。例如,假設(shè)我們有一個(gè)看起來像這樣的 User 類型:

        type User = {  firstName: string;  lastName: string;};

        我們可以創(chuàng)建一個(gè)返回用戶全名的函數(shù),如下所示:

        function getUserFullName(user: User): string {  return `${user.firstName} ${user.lastName}`;}

        大多數(shù)時(shí)候 TypeScript 足夠聰明,可以推斷出函數(shù)的返回類型,因此,在這種情況下,我們可以從函數(shù)聲明中刪除返回類型:

        function getUserFullName(user: User) {  return `${user.firstName} ${user.lastName}`;}

        請(qǐng)注意,我們刪除了 : string 部分,它是函數(shù)的返回類型。當(dāng)我們?cè)诤瘮?shù)體中返回字符串時(shí),TypeScript 正確地假定我們的函數(shù)具有字符串返回類型。

        要現(xiàn)在調(diào)用我們的函數(shù),我們必須傳遞一個(gè)與 User 類型具有相同形狀的對(duì)象:

        type User = {  firstName: string;  lastName: string;};
        function getUserFullName(user: User) { return `${user.firstName} ${user.lastName}`;}
        const user: User = { firstName: "Jon", lastName: "Doe"};
        const userFullName = getUserFullName(user);

        此代碼將成功通過 TypeScript 類型檢查器。如果我們將鼠標(biāo)懸停在編輯器中的 userFullName 常量上,編輯器會(huì)將其類型識(shí)別為字符串。

        TypeScript 中的可選函數(shù)參數(shù)

        創(chuàng)建函數(shù)時(shí)并不總是需要所有參數(shù)。在本節(jié)中,我們將學(xué)習(xí)如何在 TypeScript 中將函數(shù)參數(shù)標(biāo)記為可選。

        要將函數(shù)參數(shù)轉(zhuǎn)換為可選參數(shù),請(qǐng)?zhí)砑?? 參數(shù)名稱后面的修飾符。給定一個(gè)類型為 T 的函數(shù)參數(shù) param1,我們可以通過添加 ? 使 param1 成為可選參數(shù),如下所示:

        param1?: T

        例如,為我們的 getUserFullName 函數(shù)添加一個(gè)可選的前綴參數(shù),它是一個(gè)可選字符串,可以作為前綴添加到用戶的全名:

        type User = {  firstName: string;  lastName: string;};
        function getUserFullName(user: User, prefix?: string) { return `${prefix ?? ''}${user.firstName} ${user.lastName}`;}

        在此代碼塊的第一個(gè)突出顯示部分中,我們正在向函數(shù)添加一個(gè)可選的前綴參數(shù),在第二個(gè)突出顯示部分中,我們將使用它作為用戶全名的前綴。為此,我們正在使用無效合并運(yùn)算符 ??。這樣,我們將僅使用已定義的前綴值;否則,該函數(shù)將使用空字符串。

        現(xiàn)在,我們可以使用或不使用前綴參數(shù)調(diào)用我們的函數(shù),如下所示:

        type User = {  firstName: string;  lastName: string;};
        function getUserFullName(user: User, prefix?: string) { return `${prefix ?? ''} ${user.firstName} ${user.lastName}`;}
        const user: User = { firstName: "Jon", lastName: "Doe"};
        const userFullName = getUserFullName(user);const mrUserFullName = getUserFullName(user, 'Mr. ');

        在這種情況下,userFullName 的值為 Jon Doe,而 mrUserFullName 的值為 Mr. Jon Doe。

        請(qǐng)注意,我們不能在必需參數(shù)之前添加可選參數(shù);它必須在系列的最后列出,就像 (user: User, prefix?: string) 一樣。首先,列出它會(huì)使 TypeScript Compiler 返回錯(cuò)誤 1016:

        OutputA required parameter cannot follow an optional parameter. (1016)

        鍵入的箭頭函數(shù)表達(dá)式

        到目前為止,本教程已經(jīng)展示了如何在 TypeScript 中鍵入使用 function 關(guān)鍵字定義的普通函數(shù)。但在 JavaScript 中,我們可以通過多種方式定義函數(shù),例如使用箭頭函數(shù)。在本節(jié)中,我們將向 TypeScript 中的箭頭函數(shù)添加類型。

        向箭頭函數(shù)添加類型的語法與向普通函數(shù)添加類型幾乎相同。為了說明這一點(diǎn),請(qǐng)將?getUserFullName 函數(shù)更改為箭頭函數(shù)表達(dá)式:

        const getUserFullName = (user: User, prefix?: string) => `${prefix ?? ''}${user.firstName} ${user.lastName}`;

        如果我們想明確說明函數(shù)的返回類型,可以在 () 之后添加它,如以下代碼塊中突出顯示的代碼所示:

        const getUserFullName = (user: User, prefix?: string): string => `${prefix ?? ''}${user.firstName} ${user.lastName}`;

        現(xiàn)在,我們可以像以前一樣使用你的函數(shù)了:

        type User = {  firstName: string;  lastName: string;};
        const getUserFullName = (user: User, prefix?: string) => `${prefix ?? ''}${user.firstName} ${user.lastName}`;
        const user: User = { firstName: "Jon", lastName: "Doe"};
        const userFullName = getUserFullName(user);

        這將毫無錯(cuò)誤地通過 TypeScript 類型檢查器。

        注意:請(qǐng)記住,對(duì) JavaScript 中的函數(shù)有效的所有內(nèi)容也對(duì) TypeScript 中的函數(shù)有效。

        函數(shù)類型

        在前面的內(nèi)容中,我們向 TypeScript 中的函數(shù)的參數(shù)和返回值添加了類型。在本節(jié)中,我們將學(xué)習(xí)如何創(chuàng)建函數(shù)類型,它們是表示特定函數(shù)簽名的類型。在將函數(shù)傳遞給其他函數(shù)時(shí),創(chuàng)建與特定函數(shù)匹配的類型特別有用,例如,具有本身就是函數(shù)的參數(shù)。這是創(chuàng)建接受回調(diào)的函數(shù)時(shí)的常見模式。

        創(chuàng)建函數(shù)類型的語法類似于創(chuàng)建箭頭函數(shù),但有兩點(diǎn)不同:

        • 我們刪除了函數(shù)體。

        • 我們使函數(shù)聲明返回返回類型本身。

        以下是創(chuàng)建與我們一直使用的 getUserFullName 函數(shù)匹配的類型的方法:

        type User = {  firstName: string;  lastName: string;};
        type PrintUserNameFunction = (user: User, prefix?: string) => string;

        在此示例中,我們使用 type 關(guān)鍵字聲明了一個(gè)新類型,然后,為括號(hào)中的兩個(gè)參數(shù)提供了類型,并為箭頭后面的返回值提供了類型。

        舉一個(gè)更具體的例子,假設(shè)我們正在創(chuàng)建一個(gè)名為 onEvent 的事件偵聽器函數(shù),它接收事件名稱作為第一個(gè)參數(shù),第二個(gè)參數(shù)接收事件回調(diào)。事件回調(diào)本身將接收具有以下類型的對(duì)象作為第一個(gè)參數(shù):

        type EventContext = {  value: string;};

        然后,我們可以像這樣編寫 onEvent 函數(shù):

        type EventContext = {  value: string;};
        function onEvent(eventName: string, eventCallback: (target: EventContext) => void) { // ... implementation}

        注意 eventCallback 參數(shù)的類型是一個(gè)函數(shù)類型:

        eventCallback: (target: EventTarget) => void

        這意味著我們的 onEvent 函數(shù)需要在 eventCallback 參數(shù)中傳遞另一個(gè)函數(shù)。此函數(shù)應(yīng)接受 EventTarget 類型的單個(gè)參數(shù)。我們的 onEvent 函數(shù)會(huì)忽略此函數(shù)的返回類型,因此,我們使用 void 作為類型。

        使用類型化異步函數(shù)

        在使用 JavaScript 時(shí),使用異步函數(shù)是比較常見的。TypeScript 有一種特定的方法來處理這個(gè)問題。在本節(jié)中,我們將在 TypeScript 中創(chuàng)建異步函數(shù)。

        創(chuàng)建異步函數(shù)的語法與用于 JavaScript 的語法相同,但添加了允許類型:

        async function asyncFunction(param1: number) {  // ... function implementation ...}

        向普通函數(shù)添加類型和向異步函數(shù)添加類型之間有一個(gè)主要區(qū)別:在異步函數(shù)中,返回類型必須始終是 Promise 泛型。Promise 泛型表示由異步函數(shù)返回的 Promise 對(duì)象,其中 T 是 promise 解析為的值的類型。

        假設(shè)我們有一個(gè)用戶類型:

        type User = {  id: number;  firstName: string;};

        還想象一下,我們?cè)跀?shù)據(jù)存儲(chǔ)中有一些用戶對(duì)象。這些數(shù)據(jù)可以存儲(chǔ)在任何地方,例如文件、數(shù)據(jù)庫或 API 請(qǐng)求后面。為簡(jiǎn)單起見,在此示例中,我們將使用數(shù)組:

        type User = {  id: number;  firstName: string;};
        const users: User[] = [ { id: 1, firstName: "Jane" }, { id: 2, firstName: "Jon" }];

        如果我們想創(chuàng)建一個(gè)類型安全的函數(shù),以異步方式按 ID 檢索用戶,我們可以這樣做:

        async function getUserById(userId: number): Promise {  const foundUser = users.find(user => user.id === userId);
        if (!foundUser) { return null; }
        return foundUser;}

        在此函數(shù)中,我們首先將函數(shù)聲明為異步:

        async function getUserById(userId: number): Promise {

        然后,我們指定它接受作為第一個(gè)參數(shù)的用戶 ID,它必須是一個(gè)數(shù)字:

        async function getUserById(userId: number): Promise {

        getUserById 的返回類型是一個(gè) Promise,它解析為 User 或 null。我們正在使用聯(lián)合類型 User | null 作為 Promise 泛型的類型參數(shù)。

        用戶 | null 是 Promise 中的 T:

        async function getUserById(userId: number): Promise {

        使用 await 調(diào)用我們的函數(shù)并將結(jié)果存儲(chǔ)在名為 user 的變量中:

        type User = {  id: number;  firstName: string;};
        const users: User[] = [ { id: 1, firstName: "Jane" }, { id: 2, firstName: "Jon" }];
        async function getUserById(userId: number): Promise { const foundUser = users.find(user => user.id === userId);
        if (!foundUser) { return null; }
        return foundUser;}
        async function runProgram() { const user = await getUserById(1);}

        注意:我們正在使用一個(gè)名為 runProgram 的包裝函數(shù),因?yàn)?,我們不能在文件的頂層使?await。這樣做會(huì)導(dǎo)致 TypeScript 編譯器發(fā)出錯(cuò)誤 1375:

        輸出'await' 表達(dá)式僅在文件是模塊時(shí)才允許在文件的頂層使用,但該文件沒有導(dǎo)入或?qū)С?。考慮添加一個(gè)空的“export {}”以使該文件成為一個(gè)模塊。(1375)

        如果我們?cè)诰庉嬈骰?TypeScript Playground 中將鼠標(biāo)懸停在 user 上,我們會(huì)發(fā)現(xiàn) user 的類型為 User | null,這正是我們的 getUserById 函數(shù)返回的承諾解析為的類型。

        如果刪除 await 并直接調(diào)用該函數(shù),則返回 Promise 對(duì)象:

        async function runProgram() {  const userPromise = getUserById(1);}

        如果,我們將鼠標(biāo)懸停在 userPromise 上,我們會(huì)發(fā)現(xiàn)它的類型是 Promise?null>。

        大多數(shù)時(shí)候,TypeScript 可以推斷異步函數(shù)的返回類型,就像它對(duì)非異步函數(shù)所做的那樣。

        因此,您可以省略 getUserById 函數(shù)的返回類型,因?yàn)樗匀槐徽_推斷為具有類型 Promise?null>:

        async function getUserById(userId: number) {  const foundUser = users.find(user => user.id === userId);
        if (!foundUser) { return null; }
        return foundUser;}

        為 Rest 參數(shù)添加類型

        剩余參數(shù)是 JavaScript 中的一項(xiàng)功能,它允許函數(shù)以單個(gè)數(shù)組的形式接收許多參數(shù)。在本節(jié)中,我們將在 TypeScript 中使用剩余參數(shù)。

        通過使用 rest 參數(shù)后跟結(jié)果數(shù)組的類型,完全可以以類型安全的方式使用 rest 參數(shù)。以下面的代碼為例,其中有一個(gè)名為 sum 的函數(shù),它接受可變數(shù)量的數(shù)字并返回它們的總和:

        function sum(...args: number[]) {  return args.reduce((accumulator, currentValue) => {    return accumulator + currentValue;  }, 0);}

        該函數(shù)使用 .reduce Array 方法迭代數(shù)組并將元素相加。請(qǐng)注意此處突出顯示的其余參數(shù) args。類型被設(shè)置為一個(gè)數(shù)字?jǐn)?shù)組:number[]。

        調(diào)用我們的函數(shù)正常工作:

        function sum(...args: number[]) {  return args.reduce((accumulator, currentValue) => {    return accumulator + currentValue;  }, 0);}
        const sumResult = sum(2, 4, 6, 8);

        如果我們使用數(shù)字以外的任何內(nèi)容調(diào)用我們的函數(shù),例如:

        const sumResult = sum(2, "b", 6, 8);

        TypeScript 編譯器將發(fā)出錯(cuò)誤 2345:

        OutputArgument of type 'string' is not assignable to parameter of type 'number'. (2345)

        使用函數(shù)重載

        程序員有時(shí)需要一個(gè)函數(shù)來接受不同的參數(shù),具體取決于函數(shù)的調(diào)用方式。在 JavaScript 中,這通常是通過有一個(gè)參數(shù)來完成的,該參數(shù)可以采用不同類型的值,如字符串或數(shù)字。將多個(gè)實(shí)現(xiàn)設(shè)置為相同的函數(shù)名稱稱為函數(shù)重載。

        使用 TypeScript,我們可以創(chuàng)建函數(shù)重載,明確描述它們處理的不同情況,通過分別記錄重載函數(shù)的每個(gè)實(shí)現(xiàn)來改善開發(fā)人員體驗(yàn)。

        本節(jié)將介紹如何在 TypeScript 中使用函數(shù)重載。

        假設(shè)我們有一個(gè)用戶類型:

        type User = {  id: number;  email: string;  fullName: string;  age: number;};

        并且我們想創(chuàng)建一個(gè)可以使用以下任何信息查找用戶的函數(shù):

        • ID

        • 電子郵件

        • 年齡和全名

        我們可以像這樣創(chuàng)建這樣的函數(shù):

        function getUser(idOrEmailOrAge: number | string, fullName?: string): User | undefined {  // ... code}

        該函數(shù)使用 | 運(yùn)算符為 idOrEmailOrAge 和返回值組成類型的聯(lián)合。

        接下來,為我們希望使用函數(shù)的每種方式添加函數(shù)重載,如以下突出顯示的代碼所示:

        type User = {  id: number;  email: string;  fullName: string;  age: number;};
        function getUser(id: number): User | undefined;function getUser(email: string): User | undefined;function getUser(age: number, fullName: string): User | undefined;
        function getUser(idOrEmailOrAge: number | string, fullName?: string): User | undefined { // ... code}

        此函數(shù)具有三個(gè)重載,每個(gè)重載一個(gè)用于檢索用戶。創(chuàng)建函數(shù)重載時(shí),在函數(shù)實(shí)現(xiàn)本身之前添加函數(shù)重載。函數(shù)重載沒有主體;他們只有參數(shù)列表和返回類型。

        接下來,實(shí)現(xiàn)函數(shù)本身,它應(yīng)該有一個(gè)與所有函數(shù)重載兼容的參數(shù)列表。在前面的示例中,我們的第一個(gè)參數(shù)可以是數(shù)字或字符串,因?yàn)樗梢允?id、電子郵件或年齡:

        function getUser(id: number): User | undefined;function getUser(email: string): User | undefined;function getUser(age: number, fullName: string): User | undefined;
        function getUser(idOrEmailOrAge: number | string, fullName?: string): User | undefined { // ... code}

        因此,我們?cè)诤瘮?shù)實(shí)現(xiàn)中將 idOrEmailorAge 參數(shù)的類型設(shè)置為 number | string。這樣,它就與 getUser 函數(shù)的所有重載兼容。

        我們還為函數(shù)添加了一個(gè)可選參數(shù),用于當(dāng)用戶傳遞全名時(shí):

        function getUser(id: number): User | undefined;function getUser(email: string): User | undefined;function getUser(age: number, fullName: string): User | undefined;
        function getUser(idOrEmailOrAge: number | string, fullName?: string): User | undefined { // ... code}

        實(shí)現(xiàn)的功能可能如下所示,其中,我們使用用戶數(shù)組作為用戶的數(shù)據(jù)存儲(chǔ):

        type User = {  id: number;  email: string;  fullName: string;  age: number;};
        const users: User[] = [ { id: 1, email: "[email protected]", fullName: "Jane Doe" , age: 35 }, { id: 2, email: "[email protected]", fullName: "Jon Doe", age: 35 }];
        function getUser(id: number): User | undefined;function getUser(email: string): User | undefined;function getUser(age: number, fullName: string): User | undefined;
        function getUser(idOrEmailOrAge: number | string, fullName?: string): User | undefined { if (typeof idOrEmailOrAge === "string") { return users.find(user => user.email === idOrEmailOrAge); }
        if (typeof fullName === "string") { return users.find(user => user.age === idOrEmailOrAge && user.fullName === fullName); } else { return users.find(user => user.id === idOrEmailOrAge); }}
        const userById = getUser(1);const userByEmail = getUser("[email protected]");const userByAgeAndFullName = getUser(35, "Jon Doe");

        在此代碼中,如果 idOrEmailOrAge 是一個(gè)字符串,那么,我們可以使用電子郵件鍵搜索用戶。以下條件假設(shè) idOrEmailOrAge 是一個(gè)數(shù)字,因此,它是 id 或年齡,具體取決于是否定義了 fullName。

        函數(shù)重載的一個(gè)有趣的方面是,在大多數(shù)編輯器中,包括 VS Code 和 TypeScript Playground,只要我們鍵入函數(shù)名稱并打開第一個(gè)括號(hào)來調(diào)用函數(shù),就會(huì)出現(xiàn)一個(gè)彈出窗口,其中包含所有可用的重載, 如下圖所示:

        如果我們?yōu)槊總€(gè)函數(shù)重載添加注釋,該注釋也將作為文檔來源出現(xiàn)在彈出窗口中。例如,將以下突出顯示的注釋添加到示例重載中:

        .../** * Get a user by their ID. */function getUser(id: number): User | undefined;/** * Get a user by their email. */function getUser(email: string): User | undefined;/** * Get a user by their age and full name. */function getUser(age: number, fullName: string): User | undefined;...

        現(xiàn)在,當(dāng)我們將鼠標(biāo)懸停在這些函數(shù)上時(shí),將為每個(gè)重載顯示注釋,如下面的動(dòng)畫所示:

        用戶定義的類型保護(hù)

        本教程將檢查 TypeScript 中函數(shù)的最后一個(gè)特性是用戶定義的類型保護(hù),它們是允許 TypeScript 更好地推斷某些值的類型的特殊函數(shù)。這些守衛(wèi)在條件代碼塊中強(qiáng)制執(zhí)行某些類型,其中值的類型可能會(huì)根據(jù)情況而有所不同。這些在使用 Array.prototype.filter 函數(shù)返回過濾的數(shù)據(jù)數(shù)組時(shí)特別有用。

        有條件地向數(shù)組添加值時(shí)的一項(xiàng)常見任務(wù)是檢查某些條件,然后,僅在條件為真時(shí)才添加值。如果該值不為真,則代碼向數(shù)組添加一個(gè)假布爾值。在使用該數(shù)組之前,我們可以使用 .filter(Boolean) 對(duì)其進(jìn)行過濾,以確保僅返回真實(shí)值。

        當(dāng)使用值調(diào)用時(shí),布爾構(gòu)造函數(shù)返回 true 或 false,具體取決于此值是 Truthy 還是 Falsy 值。

        例如,假設(shè)我們有一個(gè)字符串?dāng)?shù)組,并且如果其他標(biāo)志為真,我們只想將字符串產(chǎn)生式包含到該數(shù)組中:

        const isProduction = false
        const valuesArray = ['some-string', isProduction && 'production']
        function processArray(array: string[]) { // do something with array}
        processArray(valuesArray.filter(Boolean))

        雖然,這是在運(yùn)行時(shí)完全有效的代碼,但 TypeScript 編譯器會(huì)在編譯期間為我們提供錯(cuò)誤 2345:

        OutputArgument of type '(string | boolean)[]' is not assignable to parameter of type 'string[]'. Type 'string | boolean' is not assignable to type 'string'.   Type 'boolean' is not assignable to type 'string'. (2345)

        此錯(cuò)誤表示,在編譯時(shí),傳遞給 processArray 的值被解釋為 false | 的數(shù)組。字符串值,這不是 processArray 所期望的。它需要一個(gè)字符串?dāng)?shù)組:string[]。

        這是 TypeScript 不夠聰明的一種情況,無法通過使用 .filter(Boolean) 來推斷我們正在從數(shù)組中刪除所有虛假值。但是,有一種方法可以向 TypeScript 提供這個(gè)提示:使用用戶定義的類型保護(hù)。

        創(chuàng)建一個(gè)名為 isString 的用戶定義類型保護(hù)函數(shù):

        function isString(value: any): value is string {  return typeof value === "string"}

        注意 isString 函數(shù)的返回類型。創(chuàng)建用戶定義類型保護(hù)的方法是使用以下語法作為函數(shù)的返回類型:

        parameterName is Type

        其中 parameterName 是我們正在測(cè)試的參數(shù)的名稱,Type 是此函數(shù)返回 true 時(shí)此參數(shù)值的預(yù)期類型。

        在這種情況下,如果 isString 返回 true,則表示 value 是一個(gè)字符串。我們還將 value 參數(shù)的類型設(shè)置為 any,因此,它適用于任何類型的值。

        現(xiàn)在,更改?.filter 調(diào)用以使用的新函數(shù),而不是將其傳遞給布爾構(gòu)造函數(shù):

        const isProduction = false
        const valuesArray = ['some-string', isProduction && 'production']
        function processArray(array: string[]) { // do something with array}
        function isString(value: any): value is string { return typeof value === "string"}
        processArray(valuesArray.filter(isString))

        現(xiàn)在 TypeScript 編譯器正確地推斷出傳遞給 processArray 的數(shù)組只包含字符串,并且,我們的代碼可以正確編譯。

        結(jié)論

        函數(shù)是 TypeScript 中應(yīng)用程序的構(gòu)建塊,在本教程中,我們學(xué)習(xí)了如何在 TypeScript 中構(gòu)建類型安全的函數(shù),以及如何利用函數(shù)重載來更好地記錄單個(gè)函數(shù)的所有變體。擁有這些知識(shí)將允許在整個(gè)代碼中使用更多類型安全且易于維護(hù)的功能。


        往期推薦


        給力!快速了解Rust 模塊使用方式
        第一次拿全年年終獎(jiǎng)的前端女程序員的2021
        45 個(gè) Git 經(jīng)典操作場(chǎng)景,專治不會(huì)合代碼

        最后


        • 歡迎加我微信,拉你進(jìn)技術(shù)群,長(zhǎng)期交流學(xué)習(xí)...

        • 歡迎關(guān)注「前端Q」,認(rèn)真學(xué)前端,做個(gè)專業(yè)的技術(shù)人...

        點(diǎn)個(gè)在看支持我吧
        瀏覽 32
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
          
          

            1. 欧美黄片毛 | 蜜桃91麻豆精品一二三区 | 日本护士大口吞精视频网站 | www.肏逼 | 秋霞丝鲁片一区二区三区手机在绒免 |