如何强制TypeScript泛型仅包含指定属性,禁止额外属性?
解决TypeScript中FormFields嵌套对象的严格属性约束问题
你当前的问题核心在于T extends FormFields是结构兼容检查——只要T满足FormFields的最小结构要求,额外属性不会被限制。要实现嵌套对象仅允许value和error两个属性,需要做精确类型匹配,以下是具体方案:
方案1:使用Exact工具类型实现严格匹配
定义一个Exact工具类型,通过双向extends检查确保两个类型结构完全一致,而非单向兼容:
// 精确类型匹配工具 type Exact<T, U> = T extends U ? U extends T ? T : never : never; // 原FormFields接口保留 interface FormFields { [key: string]: { value: string; error: boolean; }; } // 修改泛型函数的约束为Exact<T, FormFields> const getFormFields = <T extends Exact<T, FormFields>>(formFields: T) => formFields;
方案2:直接约束属性为严格类型
如果不想额外定义工具类型,也可以直接把嵌套对象的类型抽离,再通过泛型约束强制每个属性与该类型完全匹配:
// 定义严格的字段类型,无扩展空间 type StrictFormField = { value: string; error: boolean }; // 泛型约束T的所有属性必须严格等于StrictFormField const getFormFields = <T extends { [K in keyof T]: StrictFormField }>( formFields: T extends Record<keyof T, StrictFormField> ? T : never ) => formFields;
验证效果
- 合法示例(无额外属性,正常通过):
const validForm = getFormFields({ username: { value: "john_doe", error: false }, email: { value: "", error: true } });
- 非法示例(存在额外属性,TypeScript报错):
// 报错:类型"{ value: string; error: boolean; extra: string; }"不能赋值给类型"StrictFormField" const invalidForm = getFormFields({ username: { value: "john_doe", error: false, extra: "invalid" } });
原理说明
两种方案的核心都是通过双向类型检查替代单向的extends:
- 单向
extends只要求T包含FormFields的必要属性,允许额外扩展; - 双向检查则强制T的结构与目标类型完全一致,任何额外属性都会触发类型错误。
内容的提问来源于stack exchange,提问作者Abraham Arreola
相关产品推荐
相关产品推荐

