我正在嘗試為我的 FormBuilder 組件創建型別,但在屬性型別提取方面遇到了一些麻煩。
這是簡化的代碼:
interface NumericField {
type: 'numeric'
}
interface TextField {
type: 'text'
}
type Field = NumericField | TextField
type Fields = Record<string, Field>
export type PropertyTypeExtractor<T extends Fields> = {
[Property in keyof T]
: T[Property] extends NumericField ? number
: T[Property] extends TextField ? string
: never;
};
const fields = {
numericField: {
type: 'numeric'
},
textField: {
type: 'text'
}
}
const data = {
numericField: 42,
textField: 'lorem ipsum'
}
function createForm<T extends Fields>(fields: T, data: PropertyTypeExtractor<T>) { }
// fields: Type 'string' is not assignable to type '"text"'.
createForm(fields, data)
正如我所看到的,主要問題來自type Fields = Record<string, Field>,打字稿不知道究竟是哪種型別Field。就算type === 'text'意味著這可以是唯一的TextField。
打字稿足夠聰明:
const anotherFields: Fields = {
numericField: {
type: 'numeric'
},
textField: {
type: 'text'
}
}
const field = anotherFields.numericField // field: Field
if (field.type === 'numeric') {
console.log(field) // field: NumericField
}
那么這里有一些針對我的案例的解決方法嗎?
操場
uj5u.com熱心網友回復:
問題在于,Fields當作為引數傳遞給函式時,打字稿正在評估和擴展您的型別以鍵入。您可以通過以下幾種方式解決此問題:
- 將欄位直接傳遞給行內函式:
createForm({
numericField: {
type: 'numeric'
},
textField: {
type: 'text'
}
}, data)
- 使用
as const防止型別的欄位變數的擴大:
const fields2 = {
numericField: {
type: 'numeric'
},
textField: {
type: 'text'
}
} as const;
createForm(fields, data)
- 加入一種引數型別,因此推斷適用于整個物件。我不是 100% 關于為什么這有效的基本原理 - 但我相信這與對同時發生的型別的推斷有關,而不是在比較兩種不同的型別時試圖找到最合適的:
type FormParameters<T extends Fields> = { fields: T, data: PropertyTypeExtractor<T> };
function createForm<T extends FormParameters<any>>(parameters: T){ }
createForm({ fields, data })
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/326555.html
