如何让TypeScript函数仅接受映射为特定类型的键?
如何让函数仅接受映射为特定类型的键?
给定以下代码:
type Foo = { // 任意类型均可 foo: number; bar: number; baz: string; } function f<T>(obj: T, key: keyof T) { const foo = obj[key] // foo的类型应为number } const x: Foo = {foo: 0, bar: 1, baz: "a"} f(x, "foo") // 合法 f(x, "bar") // 合法 f(x, "baz") // 应报错,因为x["baz"]的类型不是number
尝试过扩展T,但无法关联参数中的键:
function f<T extends {key: number}>(obj: T, key: keyof T) {} // 无效
还尝试提取Foo中类型为number的字段键,但Extract未按预期工作:
function f<T>(obj: T, key: keyof (Extract<T, number>))) {} // 同样无效
这在TypeScript中可行吗?
解决方案
完全可行,通过双重泛型约束即可实现:同时限制键的范围,以及该键对应值的类型。
写法一:双重泛型约束
type Foo = { foo: number; bar: number; baz: string; } // 约束K为T的键,且T[K]必须是number类型 function f<T, K extends keyof T>(obj: T, key: K): T[K] { return obj[key]; // 返回值类型自动推导为number(符合约束时) } const x: Foo = {foo: 0, bar: 1, baz: "a"} f(x, "foo") // 合法,返回number f(x, "bar") // 合法,返回number f(x, "baz") // 报错:类型'"baz"'的参数不能赋给类型'"foo" | "bar"'的参数
写法二:自定义条件类型提取键
如果需要预定义符合条件的键集合,可以用条件类型构造:
// 提取对象T中值类型为U的键 type KeysOfType<T, U> = { [K in keyof T]: T[K] extends U ? K : never }[keyof T] type Foo = { foo: number; bar: number; baz: string; } function f<T>(obj: T, key: KeysOfType<T, number>) { const foo = obj[key]; // foo类型为number } const x: Foo = {foo: 0, bar: 1, baz: "a"} f(x, "foo") // 合法 f(x, "bar") // 合法 f(x, "baz") // 报错
为什么之前的尝试无效?
- 第一种写法中
T extends {key: number}的key是固定字面量,无法和传入的key参数动态关联,约束不生效; Extract<T, number>用法错误:Extract用于从联合类型中提取成员,不能直接从对象类型中筛选值为特定类型的键。
内容的提问来源于stack exchange,提问作者Gbox4
相关产品推荐
相关产品推荐

