我有以下功能:
const fieldDefinitions = {
a: { id: "14", "default": "none" },
b: { id: "15", "default": 0 },
c: { id: "16", "default": 0 },
};
const setFields = <T extends typeof fieldDefinitions, K extends keyof T>(fieldValues: { fieldName: K, value: T[K]["default"] }[]) => {
//logic to set fields
}
我想以一种只接受与默认值类型相同的字段值的方式键入它。
例如:
setFields([
{ fieldName: "a", value: "somestring" },
{ fieldName: "c", value: 123 },
])
//should work because:
// - default of a is "none" which is a string
// - default of c is 0 which is a number
setFields([
{ fieldName: "a", value: 123 },
{ fieldName: "c", value: "somestring" },
])
//should NOT work because:
// - default of a is "none" which is a string, but a number is given
// - default of c is 0 which is a number, but a string is given
这是我在类型定义中遇到错误的地方:
value: T[K]["default"]
它说:类型“default”不能用于索引类型“T[K]”
所以我的问题是,在这里访问 T[K] 的“默认”属性的类型的正确方法是什么?
这是 TypeScript Playground 中的代码:
最佳答案
如果T
扩展typeof fieldDefinitions
,这意味着它可以是具有任何其他属性的任何子类型,而这些属性不具有default
的对象类型.
T
并未真正使用,您只希望 fieldDefinitions
不是它的子类型,因此您可以执行以下操作:
type FieldDefinitions = typeof fieldDefinitions
/**
* The field value should be enforced to be the same type as the default value in the definition
*/
const setFields = <K extends keyof FieldDefinitions>(fieldValues: { fieldName: K, value: FieldDefinitions[K]["default"] }[]) => {
//logic to set fields
}
但是,这不会真正解决您想要解决的问题。它不能确保在数组的元素中,键和值是相关的(值
将被键入为所有现有键的联合)
这里真正的解决方案是使用映射类型作为参数。这种技术有时称为反向映射类型,将确保 TS 能够遵循数组每个元素内的相关性:
const fieldDefinitions = {
a: { id: "14", "default": "none" },
b: { id: "15", "default": 0 },
c: { id: "16", "default": 0 },
};
type FieldValues<T> = {
[P in keyof T]: { fieldName: T[P], value: typeof fieldDefinitions[T[P] & FieldDefinitionKeys]['default'] }
}
type FieldDefinitionKeys = keyof typeof fieldDefinitions
const setFields = <T extends [FieldDefinitionKeys] | FieldDefinitionKeys[]>(fieldValues: FieldValues<T>) => {
}
// works
setFields([
{ fieldName: "a", value: "somestring" },
{ fieldName: "c", value: 123 },
])
//does not work
setFields([
{ fieldName: "a", value: 123 },
{ fieldName: "c", value: "somestring" },
])
关于typescript - 如何访问 : K extends keyof T, T[K] 的嵌套类型,例如T[K] ["someSubField"],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73384699/