You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript泛型函数:如何实现按键匹配对应类型属性值的校验

如何实现键与对应属性值严格匹配的泛型函数

我需要编写一个泛型函数,接收两个参数:第一个是给定类型的键,第二个必须是该类型对应此键的属性值。比如给定类型:

type Example = {
  letter: 'a' | 'b' | 'c';
  number: 1 | 2 | 3;
}

希望以下调用是合法的:

myFunction<Example>('letter', 'a');
myFunction<Example>('letter', 'c');
myFunction<Example>('number', 1);
myFunction<Example>('number', 2);

以下调用是非法的:

myFunction<Example>('letter', 1);
myFunction<Example>('letter', 2);
myFunction<Example>('number', 'b');
myFunction<Example>('number', 'c');

目前我的实现如下,但不符合需求:

type MyProperties = {
  size: 'small' | 'medium' | 'large';
  type: 'a' | 'b' | 'c';
}

/**
 * 第二个参数的类型不符合预期,因为即使传入的key是'size',它也会接受所有可能的值'small'、'medium'、'large'、'a'、'b'或'c'。
 */
function testing<P>( key: keyof P, value: P[typeof key] ) {
  //
}

// 当前实现的效果:

testing<MyProperties>('size', 'small');      // 符合预期
testing<MyProperties>('size', 'medium');     // 符合预期
testing<MyProperties>('size', 'large');      // 符合预期
testing<MyProperties>('size', 'a');          // 符合预期(不符合需求)
testing<MyProperties>('size', 'b');          // 符合预期(不符合需求)
testing<MyProperties>('size', 'c');          // 符合预期(不符合需求)
testing<MyProperties>('size', 'something');  // 不符合预期

// 我期望的效果是:

testing<MyProperties>('size', 'small');      // 符合预期
testing<MyProperties>('size', 'medium');     // 符合预期
testing<MyProperties>('size', 'large');      // 符合预期
testing<MyProperties>('size', 'a');          // 不符合预期:'a'不是'size'的有效值
testing<MyProperties>('size', 'b');          // 不符合预期:'b'不是'size'的有效值
testing<MyProperties>('size', 'c');          // 不符合预期:'c'不是'size'的有效值
testing<MyProperties>('size', 'something');  // 不符合预期:'something'不是'size'的有效值

请问这种需求是否可以实现?


可以实现,问题出在当前的泛型定义上——只声明泛型P时,key: keyof P是所有键的联合类型,P[typeof key]会被推断为P所有属性值的联合(即P[keyof P]),所以第二个参数会接受任意属性的有效值。

要解决这个问题,需要增加一个泛型参数K来约束具体的键,让TypeScript能够跟踪当前传入的是哪个键,从而准确推断对应属性值的类型:

type MyProperties = {
  size: 'small' | 'medium' | 'large';
  type: 'a' | 'b' | 'c';
}

function testing<P, K extends keyof P>(key: K, value: P[K]) {
  // 函数逻辑
}

// 验证效果:
testing<MyProperties, 'size'>('size', 'small');      // ✅ 合法
testing<MyProperties, 'size'>('size', 'medium');     // ✅ 合法
testing<MyProperties, 'size'>('size', 'large');      // ✅ 合法
testing<MyProperties, 'size'>('size', 'a');          // ❌ 非法:类型'"a"'不能赋值给类型'"small" | "medium" | "large"'
testing<MyProperties, 'size'>('size', 'b');          // ❌ 非法:同上
testing<MyProperties, 'size'>('size', 'c');          // ❌ 非法:同上
testing<MyProperties, 'size'>('size', 'something');  // ❌ 非法:类型'"something"'不能赋值给类型'"small" | "medium" | "large"'

testing<MyProperties, 'type'>('type', 'a');          // ✅ 合法
testing<MyProperties, 'type'>('type', 'b');          // ✅ 合法
testing<MyProperties, 'type'>('type', 'small');      // ❌ 非法:类型'"small"'不能赋值给类型'"a" | "b" | "c"'

甚至可以省略显式传入泛型参数,TypeScript会自动根据你传入的key推断出K的类型:

testing('size', 'small');      // ✅ 自动推断P=MyProperties,K='size'
testing('type', 'b');          // ✅ 自动推断P=MyProperties,K='type'
testing('size', 'a');          // ❌ 报错,符合预期

这种方式通过双重泛型绑定了键和对应属性值的关系,确保第二个参数只能是当前键对应的有效值,完全符合需求。

内容的提问来源于stack exchange,提问作者Rafael Berro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 14:27:03