掌握這些,ts類型聲明事半功倍 💪🏻
不要做
- 永遠不要使用類型
Number
、String
、Boolean
、Symbol
或Object
這些類型指的是非原始裝箱對象,使用number
、string
、boolean
和symbol
類型 - 不要使用
any
作為類型,除非正在將 JavaScript 項目遷移到 TypeScript - 不要將返回類型
any
用于其值將被忽略的回調,使用返回類型void
,其可以防止意外地以未經檢查的方式使用函數的返回值const fun = (fn: () => void) => {};
declare
作用?
declare
關鍵字在 TypeScript 中主要用于聲明類型信息,而不是實際的實現代碼。其幫助 TypeScript 理解代碼中的類型結構,從而提供更好的類型檢查和代碼提示等功能。
聲明全局變量類型
當在項目中使用了某些全局變量,而這些變量沒有明確的類型定義時,可以使用declare
來聲明它們的類型。
declare const globalVar: string;
如,在 UmiJS 框架 中,針對全局變量聲明類型:
// typings.d.ts
declare function log(info: string): void;
declare global {type AnalysisFunction = (params: { pageId: string; eventId: string; ext?: object }) => void;interface Window: {// 基座掛載window判斷權限方法PermissionAuth?: (params: {// 頁面唯一標識pk: string;// 按鈕唯一標識fk?: string;}) => boolean;}
}
聲明模塊
如果要使用一個外部模塊,但這個模塊沒有提供 TypeScript 的類型定義文件(.d.ts
),可以通過declare module
來聲明它的類型。
declare module 'my-custom-module' {export function doSomething(): void;
}
.d.ts
同 .ts
區別?
-
.d.ts
:第三方庫提供類型聲明、聲明全局變量或全局類型、擴展現有模塊的類型聲明// jquery.d.ts declare var jQuery: {(selector: string): any;ajax: {(url: string, settings?: any): void;}; };
-
.ts
:定義實際的類型和接口,并且這些類型和接口將被項目中的其他代碼使用時,或者在項目內部進行模塊化開發時// user.ts export interface User {id: number;name: string;email: string; }
import type
同 import
區別?
-
import type
:用于導入類型信息,但不會將導入的模塊包含在運行時代碼中。它主要用于類型聲明,不會影響最終的 JavaScript 輸出// main.ts import type { User } from './types';
-
import
:用于導入模塊中的值(如變量、函數、類等),這些值在運行時會被加載和執行。它不僅用于類型聲明,還用于實際的代碼運行
extends
擴展類型
interface
上的 extends
關鍵字允許從其他命名類型復制成員,并添加任何新成員。
這對于減少類型聲明的數量以及表明同一屬性的幾個不同的意圖很有用。
interface Person {name: string;age: number;
}
// 類型擴展
interface Man extends Person {readonly sex: '男';
}interface SpecialSkill {fly: () => void;
}
// 也可以從多種類型擴展
interface Superman extends Man, SpecialSkill {}
typeof
同 keyof
區別?
-
typeof
操作符用于獲取一個變量或屬性的類型 -
keyof
操作符用于獲取一個對象類型的所有鍵的聯合類型
interface IPerson {name: string;age: number;
}type PersonKey = keyof IPerson; // 類型是 "name" | "age"
const p: PersonKey = 'age';
const pType = typeof p; // string
更多內容,可詳見:TypeScript系列:第四篇 - typeof 與 keyof
extends keyof
類型約束
在動態訪問和操作對象屬性時保持類型安全,避免運行時錯誤。
<TData, TLabelKey extends keyof TData>
定義兩個泛型參數TData
和TLabelKey
。
TData
表示傳入的對象類型TLabelKey
表示對象中的某個鍵,該鍵必須是TData
對象的一個鍵(通過extends keyof TData
約束)
動態訪問對象屬性
動態地訪問對象的某個屬性時,可以使用這種約束來確保訪問的屬性是有效的。
interface TData {city: string;adcode: number;
}// labelKey必須是data對象的鍵之一
function getValue<TData, TLabelKey extends keyof TData>(data: TData, labelKey: TLabelKey): TData[TLabelKey] {return data[labelKey];
}
動態生成對象屬性
interface TData {city: string;adcode: number;
}// labelKey必須是data對象的鍵之一,value的類型必須與data[labelKey]的類型一致
function setProperty<TData, TLabelKey extends keyof TData>(data: TData, labelKey: TLabelKey, value: TData[TLabelKey]): TData {data[labelKey] = value;return data;
}
!
非空斷言
在不進行任何顯式檢查的情況下從類型中刪除 null
和 undefined
function liveDangerously(x?: number) {return x.toFixed(); // x可能為“未定義”return x!.toFixed(); // ??
}
- 繞過類型檢查:當確定一個變量不會是
null
或undefined
,但 TypeScript 編譯器無法確定時,使用!
來繞過類型檢查 - 避免編譯錯誤:在某些情況下,TypeScript會報錯,因為其認為一個變量可能是
null
或undefined
。使用!
可以避免編譯錯誤
模板字符串類型的排列組合
獲得一組規律固定,可由排列組合得到的聯合類型
type A = 'a1' | 'a2';
type B = 'b1' | 'b2';type Products = `${A}-${B}`; // "a1-b1" | "a1-b2" | "a2-b1" | "a2-b2"
實用工具類型
interface A {a: number;b: number;c: number;
}
interface B {c: number;d: number;
}
方法 | 作用 | 示例 | 結果 |
---|---|---|---|
Partial<Type> | 構造一個將 Type 的所有屬性設置為可選的類型 | Partial<A & B> | {a?: number, b?: number, c?: number} |
Pick<Type, Keys> | 從 Type 中選取一組屬性 Keys 來構造一個類型 | Pick<A, 'a'|'c'> | {a: number, c: number} |
Omit<Type, Keys> | 從 Type 中選擇所有屬性然后刪除 Keys 來構造一個類型 | Omit<A, 'a'|'c'> | {b: number} |
Extract<Type, Union> | 從 Type 中提取所有可分配給 Union 的聯合成員來構造一個類型 | Extract<A|B, B> | B |