問題
如何在函式的型別注釋中提取物件的屬性及其泛型型別?
我需要能夠推斷型別RequestData,以便型別正確傳播到request回呼。
目前,在呼叫此函式時,我必須request使用型別斷言撰寫回呼。我希望我的 IDEdata根據Form傳入的物件推斷型別。
此外,對于如何擺脫any我的示例中的任何建議,我們將不勝感激。
謝謝!
例子
class Field<T> {
value: T;
constructor(value: T) {
this.value = value;
}
}
class Form {
// Object containing all Field objects in this Form
fields: Record<string, Field<any>>;
constructor({ fields }: { fields: Record<string, Field<any>>; ) {
this.fields = fields;
}
}
const submit = async <Response extends unknown, RequestData extends Record<string, unknown>>(
form: Form,
request: (data: RequestData) => Promise<Response>,
): Promise<Response> => {
const fieldsAsGenerics = {} as RequestData; // Extract value stored in every form.field
return await request(fieldsAsGenerics);
};
const myForm = new Form({
fields: {
name: new Field<string>('Charlie'),
age: new Field<number | null>(66),
}
});
submit(myForm, async (data) => {
// data should be of type { [K in keyof typeof myForm.fields]: typeof myForm.fields[K] }
// which in this case is { name: string; age: number | null }
// Actual type is unknown
});
游樂場鏈接
也可以看看
- TypeScript:如何從型別中提取泛型引數?
- 將物件鍵作為通用傳遞
uj5u.com熱心網友回復:
這個問題的根源是您的Form型別不是通用的,因此編譯器不知道有關存在的欄位型別的任何資訊。一個Form物件在編譯時無法與任何其他物件區分開來Form,因此它們不能根據它們所持有的欄位型別而具有不同的行為。
因此,讓我們對其包含Form的欄位型別進行通用化Record。
class Form<T extends Record<string, Field<any>>> {
// Object containing all Field objects in this Form
fields: T
constructor({ fields }: { fields: T}) {
this.fields = fields;
}
}
現在,我們使用實用程式型別從上述記錄型別中提取 RequestData 型別(實際上,移除了 Field 包裝器)。
type ExtractFieldValues<T extends Record<string, Field<any>>> = {
[K in keyof T]: T[K] extends Field<infer V> ? V : never;
};
我們可以調整submit函式以使用新型別,但有一點需要注意。當您從Field. 編譯器不夠警覺,無法分析您可能使用的任何回圈并保證Fields已包含該型別的每個屬性:
const submit = async <Response extends unknown, Fields extends Record<string, Field<any>>>(
form: Form<Fields>,
request: (data: ExtractFieldValues<Fields>) => Promise<Response>,
): Promise<Response> => {
const fieldsAsGenerics = {
// Extract value stored in every form.field
} as ExtractFieldValues<Fields>;
// A type assertion will ALWAYS be required here:
// the compiler can't infer that you're looping over every
// property of the form type and extracting T from Field<T>.
return await request(fieldsAsGenerics);
};
為了避免型別斷言,將值直接存盤在fields沒有Field包裝器的物件中可能是明智的,但這可能是不可能的或有用的,具體取決于您的代碼的其余部分。
現在可以在使用中正確推斷型別(將滑鼠懸停在操場鏈接中進行確認):
const myForm = new Form({
fields: {
name: new Field<string>(/*Field constructor argsargs*/),
age: new Field<number | null>(/*Field constructor args*/)
}
});
submit(myForm, async (data) => {
// data should be of type { [K in keyof typeof myForm.fields]: typeof myForm.fields[K] }
// which in this case is { name: string; age: number | null }
});
游樂場鏈接
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/409678.html
標籤:
上一篇:型別'never[]'缺少來自型別'Observable<Customer[]>'的以下屬性
下一篇:回傳泛型引數的默認值
