如何创建自约束TypeScript泛型:限制group字段匹配groupNames值
TypeScript泛型约束:强制
fields.group值必须匹配groupNames定义 问题背景
现有代码尝试为不同配置名称构建泛型类型,但当前定义无法约束fields[fieldName].group必须是groupNames中的值,group字段仍允许任意字符串。需求是实现自推断的严格约束,无需单独维护TypeConfigName与GroupNames的映射关系。
现有代码:
const TypeConfigName = ['config1', 'config2'] as const; type TypeConfigName = (typeof TypeConfigName)[number]; type GroupNames<TName extends TypeConfigName> = Readonly<string[]>; type Config<TName extends TypeConfigName> = { groupNames: GroupNames<TName>; fields: { [k: string]: { group: GroupNames<TName>[number] }; }; }; const config1: Config<'config1'> = { groupNames: ['group1', 'group2'], fields: { field1: { group: 'group1' }, field2: { group: 'group2' }, }, };
解决方案
核心是通过泛型捕获groupNames的具体字面量类型,而非宽泛的string[],以此约束fields.group的取值范围。通过泛型函数实现自动推断,无需手动维护映射关系:
const TypeConfigName = ['config1', 'config2'] as const; type TypeConfigName = (typeof TypeConfigName)[number]; // 调整Config类型,新增泛型参数TGroups捕获groupNames的字面量数组类型 type Config<TName extends TypeConfigName, TGroups extends readonly string[]> = { name: TName; // 显式关联TypeConfigName约束 groupNames: TGroups; fields: { [k: string]: { group: TGroups[number] }; }; }; // 泛型函数自动推断类型,简化使用 function createConfig<TName extends TypeConfigName, TGroups extends readonly string[]>(config: Config<TName, TGroups>) { return config; } // 使用示例 const config1 = createConfig({ name: 'config1', groupNames: ['group1', 'group2'] as const, // 保留字面量类型 fields: { field1: { group: 'group1' }, field2: { group: 'group2' }, // 以下代码会触发类型错误:'group3'不在groupNames范围内 // field3: { group: 'group3' } }, }); const config2 = createConfig({ name: 'config2', groupNames: ['groupA', 'groupB'] as const, fields: { fieldX: { group: 'groupA' }, fieldY: { group: 'groupB' }, }, });
关键改动说明
- 新增TGroups泛型参数:让
Config类型依赖具体的组名字面量数组类型,而非宽泛的string[],确保fields.group的取值被严格限制。 - 泛型函数createConfig:通过函数参数自动推断
TName和TGroups类型,无需手动指定泛型参数,简化使用流程。 as const断言:保留groupNames的字面量类型,避免TypeScript将其自动推断为string[]。
内容的提问来源于stack exchange,提问作者Aaron Wilson
相关产品推荐
相关产品推荐

