你應(yīng)該掌握的 5 大 TypeScript 功能

英文 | https://betterprogramming.pub/top-5-typescript-features-you-should-master-2358db9ab3d5
翻譯 | 楊小二
TypeScript 的影響力與日俱增。它現(xiàn)在是任何新的 Web/Node 項(xiàng)目的首選配套工具。使用 TypeScript 的好處怎么強(qiáng)調(diào)都不為過。然而,了解和理解這個(gè) JavaScript 超集擁有的所有工具是很重要的。
你是否正在投入時(shí)間來提高你的TypeScript技能?你想充分利用它嗎?有時(shí),由于沒有使用正確的 TypeScript 功能并且沒有遵循其最佳實(shí)踐,可能會(huì)出現(xiàn)大量代碼重復(fù)和樣板。
在本文中,我們將研究 TypeScript 可以賦予我們的五個(gè)最重要的功能。通過確保并了解它們的用例,我們可以構(gòu)建更好、更全面的代碼庫。
1、Unions
聯(lián)合是最基本且易于使用的 TypeScript 功能之一。它們讓我們可以輕松地將多種類型合二為一。交集和聯(lián)合類型是我們組合類型的方法之一。
function logIdentifier(id: string | number) {console.log('id', id);}
當(dāng)我們想要表示某個(gè)類型可以為空時(shí),它們非常有用:
function logIdentifier(id: string | undefined) {if(!id) {console.error('no identifier found');} else {console.log('id', id);}}
不僅限于未定義或原語。它們可用于任何接口或類型。
interface Vehicle {speed: number;}interface Bike extends Vehicle {ride: () => void;}interface Plane extends Vehicle {fly: () => void;}function useVehicle(vehicle: Bike | Plane) {...}
鑒于上面的聯(lián)合類型,我們?nèi)绾螀^(qū)分自行車和飛機(jī)?通過使用可區(qū)分聯(lián)合功能。我們將創(chuàng)建一個(gè)名為 Vehicles 的枚舉并將其用作屬性值。
看看代碼如何:
enum Vehicles {bike,plane}interface Vehicle {speed: number;type: Vehicles;}interface Bike extends Vehicle {ride: () => void;type: Vehicles.bike;}interface Plane extends Vehicle {fly: () => void;type: Vehicles.plane;}function useVehicle(vehicle: Bike | Plane) {if (vehicle.type === Vehicles.bike) {vehicle.ride();}if (vehicle.type === Vehicles.plane) {vehicle.fly();}}
從而,我們可以看到Unions是一個(gè)簡單而強(qiáng)大的工具,它有一些技巧。但是,如果我們想以更強(qiáng)大和動(dòng)態(tài)的方式表達(dá)類型/接口,我們需要使用泛型。
2、泛型
使我們的方法/API 可重用的最佳方法是什么?泛型! 這是大多數(shù)類型語言中的一項(xiàng)功能。它讓我們以更通用的方式表達(dá)類型。這將賦予我們的類和類型。
讓我們從一個(gè)基本的例子開始。讓我們創(chuàng)建一個(gè)方法來將任何定義的類型添加到數(shù)組中:
function addItem(item: string, array: string[]) {array = [...array, item];return array;}
如果我們想為 int 類型創(chuàng)建相同的實(shí)用程序怎么辦?我們應(yīng)該重做同樣的方法嗎?通過簡單地使用泛型,我們可以重用代碼而不是添加更多樣板:
function addItem<T>(item: T, array: T[]) {array = [...array, item];return array;}addItem('hello', []);addItem(true, [true, true]);
我們?nèi)绾畏乐乖?T 中使用不需要的類型?為此,我們可以使用 extends 關(guān)鍵字:
function addItem<T extends boolean | string>(item: T, array: T[]) {array = [...array, item];return array;}addItem('hello', []);addItem(true, [true, true]);addItem(new Date(), []);// ^^^^^^^^^^// Argument of type 'Date' is not assignable to parameter of type 'string | boolean'
泛型將使我們能夠?yàn)槲覀兊念愋蜆?gòu)建全面和動(dòng)態(tài)的接口。它們是必須掌握的功能,需要在我們的日常開發(fā)中出現(xiàn)。
3、元組
什么是元組?我們來看看定義:
“元組類型允許你用固定數(shù)量的元素來表達(dá)數(shù)組,這些元素的類型是已知的,但不必相同。例如,你可能希望將一個(gè)值表示為一對(duì)字符串和一個(gè)數(shù)字。”
——TypeScript 的文檔
最重要的一點(diǎn)是這些數(shù)組的值長度是固定的。定義元組有兩種方式:
明確:
const array: [string, number] = ['test', 12];隱含地:
const array = ['test', 12] as const;唯一的區(qū)別是 as const 將使數(shù)組只讀,這在我看來是可取的。
請(qǐng)注意,元組也可以被標(biāo)記:
function foo(x: [startIndex: number, endIndex: number]) {...}
標(biāo)簽不需要我們?cè)诮鈽?gòu)時(shí)以不同的方式命名我們的變量。它們純粹是為了文檔和工具。標(biāo)簽將有助于使我們的代碼更具可讀性和可維護(hù)性。
請(qǐng)注意,使用標(biāo)記元組時(shí)有一個(gè)重要規(guī)則:標(biāo)記元組元素時(shí),元組中的所有其他元素也必須被標(biāo)記。
4、映射類型
什么是映射類型?它們是一種避免反復(fù)定義接口的方法。你可以將類型建立在另一種類型或接口的基礎(chǔ)上,從而節(jié)省手動(dòng)工作。
“當(dāng)你不想重復(fù)時(shí),有時(shí)一種類型需要基于另一種類型。映射類型建立在索引簽名的語法之上,用于聲明尚未提前聲明的屬性類型。” — TypeScript 的文檔
總而言之,映射類型允許我們基于現(xiàn)有類型創(chuàng)建新類型。
TypeScript 確實(shí)附帶了很多實(shí)用程序類型,因此我們不必在每個(gè)項(xiàng)目中重寫它們。
讓我們看看一些最常見的:Omit、Partial、Readonly、Readonly、Exclude、Extract、NonNullable 和 ReturnType。
讓我們看看其中的一個(gè)再行動(dòng)。假設(shè)我們要將名為 Teacher 的實(shí)體的所有屬性轉(zhuǎn)換為只讀。我們可以使用什么實(shí)用程序?
我們可以使用 Readonly 實(shí)用程序類型。讓我們看看它的實(shí)際效果:
interface Teacher {name: string;email: string;}type ReadonlyTeacher = Readonly<Teacher>;const t: ReadonlyTeacher = { name: 'jose', email: '[email protected]'};t.name = 'max'; // Error: Cannot assign to 'name' because it is a read-only property.(2540)
讓我們回顧一下Readonly 在底層是如何工作的:
type Readonly<T> = { readonly [P in keyof T]: T[P]; }現(xiàn)在讓我們創(chuàng)建我們的自定義實(shí)用程序以獲得樂趣。讓我們反轉(zhuǎn) Readonly 類型以創(chuàng)建一個(gè) Writable 類型:
interface Teacher {readonly name: string;readonly email: string;}type Writeable<T> = { -readonly [P in keyof T]: T[P] };const t: Writeable<Teacher> = { name: 'jose', email: '[email protected]' };t.name = 'max'; // works fine
注意:注意 - 修飾符。在這種情況下,它用于刪除 readonly 修飾符。它可用于從屬性中刪除其他修飾符,例如 ?。
5、類型保護(hù)
類型保護(hù)是一組幫助我們縮小對(duì)象類型的工具。這意味著我們可以從更一般的類型轉(zhuǎn)到更具體的類型。
有多種技術(shù)可以執(zhí)行類型保護(hù)。在本文中,我們將只關(guān)注用戶定義的類型保護(hù)。這些基本上是斷言——就像任何給定類型的函數(shù)一樣。
我們?nèi)绾问褂盟鼈儯课覀冎恍枰x一個(gè)函數(shù),它的返回類型是一個(gè)類型謂詞,它返回true/false。讓我們看看如何將 typeof 運(yùn)算符轉(zhuǎn)換為類型保護(hù)函數(shù):
function isNumber(x: any): x is number {return typeof x === "number";}function add1(value: string | number) {if (isNumber(value)) {return value +1;}return +value + 1;}
請(qǐng)注意,如果 isNumber 檢查為 false,則 TypeScript 可以假定 value 將是一個(gè)字符串,因?yàn)?x 可能是字符串或數(shù)字。
讓我們看另一個(gè)使用自定義接口的類型保護(hù)示例:
interface Hunter {hunt: () => void;}// function type guardfunction isHunter(x: unknown): x is Hunter {return (x as Hunter).hunt !== undefined;}const performAction = (x: unknown) => {if (isHunter(x)) {x.hunt();}}const animal = {hunt: () => console.log('hunt')}performAction(animal);
學(xué)習(xí)更多技能
請(qǐng)點(diǎn)擊下方公眾號(hào)
![]()

