如何在TypeScript中基于数组生成对象属性子集的对象
解决方案
要实现第三个参数必须包含keys数组中所有属性的约束,你需要通过泛型捕获keys的具体键类型,并强制第三个参数的结构与该类型匹配。以下是具体实现:
完整代码定义
type Doc<TData extends {}> = { data: TData; }; type Definition = { type: string; isKey: boolean; }; // 修改后的setData函数,通过泛型Keys关联keys与第三个参数 declare function setData< TDoc extends Doc<{}>, Keys extends keyof TDoc["data"] >( document: TDoc, keys: Keys[], definitions: Record<Keys, Definition> ): void; // 示例类型与常量 type PersonData = { name: string; age: number; email: string; }; type PersonDoc = Doc<PersonData>; const person: PersonDoc = { data: { name: "Alice", age: 30, email: "alice@example.com" } };
正确调用示例
当第三个参数包含keys中的所有属性时,类型校验通过:
// 合法:definitions包含name和age两个属性 setData(person, ["name", "age"], { name: { type: "string", isKey: true }, age: { type: "number", isKey: false } });
错误调用示例
如果第三个参数缺失keys中的任意属性,TypeScript会直接报错:
// 非法:缺失age属性,TypeScript提示错误 setData(person, ["name", "age"], { name: { type: "string", isKey: true } });
可选:禁止额外属性的实现
如果需要严格限制第三个参数只能包含keys中的属性(禁止额外键),可以定义Exact类型替代Record:
type Exact<T, U> = T & Record<Exclude<keyof U, keyof T>, never>; declare function setDataStrict< TDoc extends Doc<{}>, Keys extends keyof TDoc["data"] >( document: TDoc, keys: Keys[], definitions: Exact<Record<Keys, Definition>, typeof definitions> ): void; // 非法:多出email属性,TypeScript报错 setDataStrict(person, ["name", "age"], { name: { type: "string", isKey: true }, age: { type: "number", isKey: false }, email: { type: "string", isKey: false } });
可选:用对象参数替代多参数
如果你倾向于用单个对象整合所有输入,可采用以下写法:
declare function setDataWithObj< TDoc extends Doc<{}>, Keys extends keyof TDoc["data"] >(params: { document: TDoc; keys: Keys[]; definitions: Record<Keys, Definition>; }): void; // 调用示例 setDataWithObj({ document: person, keys: ["name", "age"], definitions: { name: { type: "string", isKey: true }, age: { type: "number", isKey: false } } });
内容的提问来源于stack exchange,提问作者Eric.M
相关产品推荐
相关产品推荐

