Visual Studio Code - 我如何查看 TypeScript 類型的完整展開契約?
如果我有一個看起來有點像這樣的類型集合:
type ValidValues = string | number | null
type ValidTypes = "text" | "time" | "unknown"
type Decorated = {
name?: string | null
type?: ValidTypes
value?: ValidValues
title: string
start: number
}
type Injected = {
extras: object
}
// overriding the types from Decorated
type Text = Decorated & Injected & {
name: string
type: "text"
value: string
}
我的實際程式碼有更多的內容,但這展示了核心概念。我不想必須信任自己能夠正確處理類型之間的關係。我希望工具能在經過所有類型運算後,顯示出 Text 的類型定義“評估”結果。
所以對於上述範例,我希望在 Text 中指定的欄位能覆蓋在 Decorated 類型中先前聲明的內容,而假設的提示工具的輸出應該會顯示像這樣的內容:
{
name: string
type: "text"
value: string
title: string
start: number
extras: object
}
有沒有方便的方法可以獲取這些資訊?
答案#1
使用 IntelliSense 顯示類型的快速資訊通常不盡如人意;對於任何給定的類型,你通常只能得到單一的表示方式,而這可能對你的用途來說過於簡略甚至過於冗長。有一些建議可以使其更靈活(例如,microsoft/TypeScript#25784 和 microsoft/TypeScript#28508),以便使用者能在 IDE 中展開或摺疊類型定義。但我不知道這些建議是否會在近期甚至遠期內被採納,所以我們不要等著它們發生。
這裡有一個我有時候會使用的類型別名,用來嘗試以你所說的方式擴展一個類型:
// expands object types one level deep
type Expand<T> = T extends infer O ? { [K in keyof O]: O[K] } : never;
// expands object types recursively
type ExpandRecursively<T> = T extends object
? T extends infer O ? { [K in keyof O]: ExpandRecursively<O[K]> } : never
: T;
這些使用條件型別推斷將型別 T「複製」到新的型別變數 O,然後使用類似同一性的映射型別遍歷複製型別的屬性。
條件型別推斷在概念上是一個無操作(no-op),但它被用來分配聯合型別並強制編譯器評估條件的“真”分支(如果你重新定義 Expand<T> 而不使用它,有時編譯器會直接 輸出 映射型別 {[K in keyof RelevantType]: RelevantType[K]},這不是你想要看到的)。
Expand 和 ExpandRecursively 的區別在於它是否僅輸出原樣的屬性類型(Expand),或者是否應該 展開 屬性類型(ExpandRecursively)。在遞歸的情況下,不嘗試深入基本類型會比較有幫助,這就是為什麼會包含 T extends object 條件的原因。
好的,讓我們看看當我們將它用在你的類型上會發生什麼。我們在你的情況下不需要 ExpandRecursively,但我們可以使用它……結果是一樣的:
type ExpandedText = Expand<Text>;
當我們在 IDE 中將滑鼠懸停在它上面時(無論是在 TypeScript Playground 還是 VSCode 中),它會顯示為:
/* type ExpandedText = {
name: string;
type: "text";
value: string;
title: string;
start: number;
extras: object;
} */
如你所願。
程式碼連結
答案#2
只是補充 jcalz 的回答,提供能用於函數的版本。
修改過的助手:
export type Expand<T> = T extends (...args: infer A) => infer R
? (...args: Expand<A>) => Expand<R>
: T extends infer O
? { [K in keyof O]: O[K] }
: never;
export type ExpandRecursively<T> = T extends (...args: infer A) => infer R
? (...args: ExpandRecursively<A>) => ExpandRecursively<R>
: T extends object
? T extends infer O
? { [K in keyof O]: ExpandRecursively<O[K]> }
: never
: T;
為了測試,我正在向 Text 類型添加一個 subobject 鍵,並添加一個函數接口:
type Text = Decorated &
Injected & {
name: string;
type: "text";
value: string;
subobject: Injected;
};
interface SomeFunction {
(...args: Text[]): Injected & { error: boolean };
}
這給出:
物件仍然運作正常:
答案#3
我發現這個 VS Code 擴展在這方面運作得非常完美:
美化 TypeScript:更好的類型預覽
它在懸停時甚至顯示深層嵌套的類型。





