TypeScript:條件型別不適用於可選參數
我有一個資料來源,我們稱它為 getData(),它會回傳物件。有時它回傳已知類型的物件(例如 Person、Animal),但有時回傳的物件形狀是未知的。
(TypeScript 遊樂場連結)
type Person = { name: string; age: number };
type Animal = { species: string };
/**
* This interface stores all known object types returned by `getData()`.
* I'm storing it as an interface instead of `Person | Animal` because I
* need to store the "code" of a known type (e.g. `"person"` for `Person` type).
*/
interface DataCategory {
person: Person;
animal: Animal;
}
/** Our data source */
const getData: Person | Animal | any = () => {
return {}; // Mocked value
};
現在我希望編寫一個輔助函數 useData() 來縮小 getData() 的返回值。它接受一個可選的參數,類型為 keyof DataCategory,並返回對應的類型。我希望當不傳入參數時,這個函數 返回 any。
const person = useData("person"); // const person: Person
const animal = useData("animal"); // const animal: Animal
const notKnown = useData(); // const notKnown: any
我已經嘗試了以下實作方法:
function useData<T extends keyof DataCategory>(category?: T) {
const data: any = getData();
return data as T extends undefined ? any : DataCategory[T];
}
const animal = useData("animal");
// ^ const animal: Animal
const notKnown = useData();
// ^ const notKnown: Person | Animal
// However, I want the above to be `const notKnown: any`
那行不通,因為 useData() 返回的是 Person | Animal 而不是 any。我該如何解決這個問題?
答案#1
預設情況下,TS 會使用約束作為它無法推斷的型別參數的型別(在這種情況下,沒有地方可以從中推斷 T)。你可以使用 any 作為預設值來改變這一點:
function useData<T extends keyof DataCategory = any>(category?: T) {
const data: any = getData();
return data as T extends undefined ? any : DataCategory[T];
}
遊樂場連結
正如 Michael Rose 在他的回答中指出的,你也可以使用重載,這對未來的讀者來說可能更容易理解。
答案#2
嘗試使用泛型的另一種方法是直接重載你的 useData 函數並指定類別:
function useData(category: "animal"): Animal;
function useData(category: "person"): Person;
function useData(): any;
function useData(category?: string): any {
return getData();
}
const animal = useData("animal");
// ^ const animal: Animal
const notKnown = useData();
// ^ const notKnown: any
