TypeScript:通过泛型键从对象获取正确的值类型
问题描述
我想编写一个简单的查询构建器,让实体的所有类型都能正确转换。例如,使用equalsTo过滤name字段时,只允许传入字符串作为值;过滤age字段时,只允许传入数字作为值。但目前value可以是Dogs类型的任意值,不符合需求,请问是否可以实现这一功能?
原代码如下:
class Dogs { name!: string; age!: number; alive!: boolean; } interface QueryBuilder<O extends object, F extends keyof O = keyof O> { equalsTo: (fieldName: F, value: O[F]) => boolean; } const queryBuilder = <O extends object>(): QueryBuilder<O> => ({ equalsTo: (fieldName, value) => true }) const qb = queryBuilder<Dogs>(); qb.equalsTo("name", 1); // 应该抛出错误:仅允许字符串作为值 qb.equalsTo("age", "Rex"); // 应该抛出错误:仅允许数字作为值
解决方案
可以实现,核心是把equalsTo改成方法级别的泛型,让TypeScript在每次调用方法时,根据传入的字段名动态推断对应的值类型,而不是提前固定泛型参数。
修改后的代码:
class Dogs { name!: string; age!: number; alive!: boolean; } // 移除QueryBuilder接口上的F泛型,把泛型移到equalsTo方法上 interface QueryBuilder<O extends object> { equalsTo: <F extends keyof O>(fieldName: F, value: O[F]) => boolean; } const queryBuilder = <O extends object>(): QueryBuilder<O> => ({ equalsTo: (fieldName, value) => true }) const qb = queryBuilder<Dogs>(); qb.equalsTo("name", 1); // ✅ 现在会抛出类型错误:number不能赋值给string qb.equalsTo("age", "Rex"); // ✅ 现在会抛出类型错误:string不能赋值给number
原理说明
原来的代码把F作为QueryBuilder接口的泛型参数,这会让O[F]变成所有字段类型的联合类型(比如string | number | boolean),所以value可以接收任意类型的值。
改成方法级泛型后,每次调用equalsTo时,TypeScript会根据传入的fieldName推断出具体的F(比如传入"name"时,F就是"name"),此时O[F]就精确对应该字段的类型(string),从而严格限制value的类型必须匹配字段类型。
内容的提问来源于stack exchange,提问作者Kaufmo
相关产品推荐
相关产品推荐

