我正在嘗試找到一種相對通用的方式來鍵入 POST 正文以及我與他們的 API 路由一起回傳的回應(在 nextjs 應用程式中)。
為此,我希望編譯器強制我為所有 API 路由添加一個body型別和一個return型別,我通過以下介面實作了這一點:
export interface PostTypeMapping extends Record<string, {body: unknown, return: unknown}> {
"/api/taskCompletions": {body: PostCompletionBody, return: void},
"/api/task": {body: PostTaskBody, return: void},
}
到現在為止還挺好。我可以在我的 API 路由中使用這種型別,如下所示:
async (req, res: NextApiResponse<PostTypeMapping["api/task"]["return"]>) => {
//...
}
但是,當我嘗試撰寫一個自動從 URL 推斷 POST 正文和回傳型別的包裝器時,我在以下行中遇到錯誤await fetch(url,:
“keyof PostTypeMapping”型別的引數不能分配給“RequestInfo”型別的引數。型別“編號”不可分配給型別“RequestInfo”
export async function fetchPost<T extends keyof PostTypeMapping>(url: T, body: PostTypeMapping[T]["body"]): Promise<PostTypeMapping[T]["return"]> {
try {
const res = await fetch(url, { // <- The error above occurs here
method: "POST",
body: JSON.stringify(body),
headers: {
"Content-Type": "application/json",
},
});
if(res.status === 201 || res.status === 204){
return;
}
return res.json();
} catch (err: any){
return {message: "Fehler: " err.message};
}
}
為什么url輸入為keyof PostTypeMapping的 可以是數字?
我進一步調查,在大多數情況下,extends Record<string, {body: unknown, return: unknown}>似乎確實做了我想要的(強制我向界面的所有條目添加正文和回傳型別),但允許數字鍵和字串。為什么?兩種不允許的情況都是好的。
export interface PostTypeMapping extends Record<string, {body: unknown, return: unknown}> {
"/api/taskCompletions": {body: PostCompletionBody, return: void},
"/api/task": {body: PostTaskBody, return: void},
1: {body: void, return: void}, // why is this legal? 1 is not a string
2: "asd" // not allowed -> Property '2' of type '"asd"' is not assignable to 'string' index type '{ body: unknown; return: unknown; }'
"asd": "asd" // not allowed -> Property '"asd"' of type '"asd"' is not assignable to 'string' index type '{ body: unknown; return: unknown; }
}
打字稿游樂場
編輯:
感謝 TJ Crowder ,可以在https://tsplay.dev/Nr5X2w找到該問題的簡化重現
uj5u.com熱心網友回復:
有關此問題的權威答案,請參閱microsoft/TypeScript#48269。
字串索引簽名始終允許使用數字鍵,因為 JavaScript 中的非symbol鍵總是首先被強制轉換為字串。所以“ number”鍵實際上應該更像“數字字串”,但 TypeScript 允許您將它們視為數字,以支持對帶有數字的陣列進行索引。
在 TypeScript 2.9 之前,keyof {[k: string]: any}應該是string. 但是 TypeScript 2.9引入了對numbersymbolkeyof. 此更改的一部分是keyof XwhereX有一個字串索引簽名現在包括number. keyof {[k: string]: any}也是如此string | number。這是按預期作業的。
但是對于像這樣的映射型別Record,編譯器不會立即以這種方式增加鍵。顯然,Record<K, V>適當的逆變是很重要的K(無論如何,根據ms/TS#48269 中的評論)。
但是Record<string, any>畢竟等價于{[k: string]: any},因此我們有一個不一致的地方。TypeScript 沒有將一致性作為其最重要的設計目標;事實上,TypeScript 的非目標是擁有可證明正確的型別系統。從某種意義上說,生產力比正確性更重要。如果修復不一致會使 TypeScript 對很多人來說非常煩人,那么最好留下不一致。這顯然是其中一種情況;根據相同的評論,這里的不一致無法消除(大概不會破壞語言的一些常用部分,例如陣列的數字鍵),所以它保持不變。
那好吧!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/460194.html
