我正在制作一個帶有columns陣列和rows陣列的 HTML 表格生成器。
目標是表生成器要求rows陣列物件中每個欄位的某些型別,具體取決于物件中相應鍵名的“型別”屬性columns。
例如,“用戶”表的一些示例引數,其中第 1 列是用戶名,第 2 列是指向該用戶個人資料的鏈接:
TableBody({
columns: [
{ key: "username", label: "Username", type: "string" },
{ key: "userProfile", label: "Profile Page", type: "link" },
],
rows: [
{
// username must be a string, according to the columns array
username: "MangoMcgee",
// userProfile must be a "link" type, according to the columns array
userProfile: { text: "Mango's home page", href: "/user/mango-mcgee" },
},
{
username: "PineapplePete",
userProfile: {
text: "Pineapple's home page",
href: "/user/pineapple-pete",
},
},
],
});
我已經像這樣定義了我的列和行:
type tableColumn<K> = {
key: K;
label: string;
type: "string" | "link";
};
type tableRow<T extends tableColumn<string>[]> = {
[key in T[number]["key"]]: "link" extends T[number]["type"]
? { text: string; href: string }
: string;
};
我被困在哪里:我的定義tableRow<T>是有缺陷的。我的問題(我認為)是我在想T[number]["type"]要么是"string"or "link",然后我可以使用條件 of"link" extends T[number]["type"]來決定屬性應該是 astring還是 a { text: string; href: string }。
但我意識到,自從我定義tableColumn<K>["type"]為 union "string" | "link",它總是這樣。它實際上不是"string" or "link",而是 的聯合本身"string" | "link"。所以這個條件總是正確的。
我想我需要在通用而不是聯合上創建type屬性。tableColumn但是如果tableColumn采用另一個泛型型別引數,我不確定我將在哪里實際傳遞型別引數。
游樂場鏈接
uj5u.com熱心網友回復:
首先,讓我們將一些“型別”映射到我們將用于結果的型別:
type ColTypes = {
string: string;
link: {
text: string;
href: string;
};
};
然后我們將創建一個型別來創建另一種型別,給定列:
type TypeFromCols<
Cols extends readonly { key: string; label: string; type: "string" | "link" }[]
> = {
[K in Cols[number]["key"]]: ColTypes[Extract<
Cols[number],
{ key: K }
>["type"]];
};
映射每個鍵,我們從陣列中提取列,然后獲取相應的型別。現在的定義TableBody如下:
type ColArgs = {
key: string;
label: string;
type: "string" | "link";
};
const TableBody = <Cols extends readonly ColArgs[]>(body: {
columns: Narrow<Cols>;
rows: readonly TypeFromCols<Cols>[];
}) => { /* ... */ };
你會注意到另一種型別,Narrow,這只是為了讓 TypeScript 將引數推斷為一個巨大的物件字面量(如果它是直接傳遞的):
type Narrow<T> =
| (T extends infer U ? U : never)
| Extract<
T,
number | string | boolean | bigint | symbol | null | undefined | []
>
| ([T] extends [[]] ? [] : { [K in keyof T]: Narrow<T[K]> });
這對結果沒有影響,只是 QoL 的事情,所以你as const在使用TableBody({ columns: { ... } as const, ... }).
操場
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/511205.html
標籤:打字稿仿制药
