通用类型:动态类型检查特定对象属性:在通用类型 B 中使用类型 A 中的键~值对
Generic Types: Dynamically type check specific object properties: using key ~ value pair from Type A, in Generic Type B
我目前有一个类型 (FieldTypeProperties),我想在它的键传递给函数或对象时强制执行动态类型检查:
export enum supportedFields{
Text = "Text",
Note = "Note",
Number = "Number"
}
export type FieldTypeProperties = {
[supportedFields.Text]: TypeA;
[supportedFields.Note]: TypeB;
[supportedFields.Number]: TypeC;
};
我已经成功地定义了一个按预期运行的函数:
const createField = <K extends keyof FieldTypeProperties>(fieldType: K, properties: FieldTypeProperties[K]): IResult => {
let field: IResult;
//Some code
return field;
}
用法按预期工作,fieldType 参数值确实检查属性参数中的正确类型:
let test = createField(supportedFields.Note, {});
// Checks for Type B in the properties argument, as defined in the FieldTypeProperties type
但是对于批处理操作,我想循环一个符合 createField() 参数的对象数组,所以:
type BatchObj<K extends keyof FieldTypeProperties> = {
fieldType: K;
properties: FieldTypeProperties[K];
}
// Intended Usage:
let testBatch1: BatchObj<keyof FieldTypeProperties>[] = [
{
fieldType: supportedFields.Text,
properties: {}, //Type A should only be checked, but it's not, instead a union of TypeA | TypeB | TypeC is checked
},
]
// Usage that works but is NOT desired:
let testBatch2: BatchObj<supportedFields.Text>[] = [
{
fieldType: supportedFields.Text,
properties: {}, //Type A is checked, but now any additional objects added to this array must have a fieldType = supportedFields.Text and properties = TypeA
}
]
我能理解为什么会这样,因为在 testBatch1 中:
fieldType (K) 将是 FieldTypeProperties 类型的 键集 ,属性 (FieldTypeProperties[K]) 将是 集 值FieldTypeProperties 类型。
根据上面代码片段中的推断,有没有办法实现我想要的用法?或者这是打字稿的限制,就目前而言是不可能的?
非常感谢您的回复:)
您可以为每个可能的键生成联合:BatchObj<"Text"> | BatchObj<"Note"> | BatchObj<"Number">
使用条件类型的分布。这将确保 fieldType
和 properties
之间的关系得以保留:
type BatchObj<K extends keyof FieldTypeProperties> = {
fieldType: K;
properties: FieldTypeProperties[K];
}
type BatchObjUnion<K extends keyof FieldTypeProperties = keyof FieldTypeProperties> = K extends K ? BatchObj<K>: never
// Intended Usage:
let testBatch1: BatchObjUnion[] = [
{
fieldType: supportedFields.Text,
properties: { text: "" }, //Type A
},
]
我目前有一个类型 (FieldTypeProperties),我想在它的键传递给函数或对象时强制执行动态类型检查:
export enum supportedFields{
Text = "Text",
Note = "Note",
Number = "Number"
}
export type FieldTypeProperties = {
[supportedFields.Text]: TypeA;
[supportedFields.Note]: TypeB;
[supportedFields.Number]: TypeC;
};
我已经成功地定义了一个按预期运行的函数:
const createField = <K extends keyof FieldTypeProperties>(fieldType: K, properties: FieldTypeProperties[K]): IResult => {
let field: IResult;
//Some code
return field;
}
用法按预期工作,fieldType 参数值确实检查属性参数中的正确类型:
let test = createField(supportedFields.Note, {});
// Checks for Type B in the properties argument, as defined in the FieldTypeProperties type
但是对于批处理操作,我想循环一个符合 createField() 参数的对象数组,所以:
type BatchObj<K extends keyof FieldTypeProperties> = {
fieldType: K;
properties: FieldTypeProperties[K];
}
// Intended Usage:
let testBatch1: BatchObj<keyof FieldTypeProperties>[] = [
{
fieldType: supportedFields.Text,
properties: {}, //Type A should only be checked, but it's not, instead a union of TypeA | TypeB | TypeC is checked
},
]
// Usage that works but is NOT desired:
let testBatch2: BatchObj<supportedFields.Text>[] = [
{
fieldType: supportedFields.Text,
properties: {}, //Type A is checked, but now any additional objects added to this array must have a fieldType = supportedFields.Text and properties = TypeA
}
]
我能理解为什么会这样,因为在 testBatch1 中: fieldType (K) 将是 FieldTypeProperties 类型的 键集 ,属性 (FieldTypeProperties[K]) 将是 集 值FieldTypeProperties 类型。
根据上面代码片段中的推断,有没有办法实现我想要的用法?或者这是打字稿的限制,就目前而言是不可能的?
非常感谢您的回复:)
您可以为每个可能的键生成联合:BatchObj<"Text"> | BatchObj<"Note"> | BatchObj<"Number">
使用条件类型的分布。这将确保 fieldType
和 properties
之间的关系得以保留:
type BatchObj<K extends keyof FieldTypeProperties> = {
fieldType: K;
properties: FieldTypeProperties[K];
}
type BatchObjUnion<K extends keyof FieldTypeProperties = keyof FieldTypeProperties> = K extends K ? BatchObj<K>: never
// Intended Usage:
let testBatch1: BatchObjUnion[] = [
{
fieldType: supportedFields.Text,
properties: { text: "" }, //Type A
},
]