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

TypeScript如何强制对象内类型统一,新增泛型后类型校验失效如何解决

问题背景

我最初实现的代码运行符合预期,能正常触发类型校验:

function test<types extends Record<string,any>>(dict: dictionary<types>){}

type dictionary<types extends Record<string, any>> = {
  [key in keyof types]: {
    bar?: types[key];
    foo?: (value:types[key])=>true;
  };
};

test({
 key1:{
  bar: 2,
  foo: (input:number)=>true,
 },
 key2:{
  bar: 'hello',
  foo: (input: number)=>true, // 正常报错:input类型应为string
 }
})

为了保留对dict参数的泛型类型引用,我修改了代码,但修改后类型校验失效,预期的报错没有出现:

function test2<
  types extends Record<string,any>,
  dictionary extends dictionary2<types> // 新增泛型类型
>(dict: dictionary){}

// 定义和之前的dictionary完全一致
type dictionary2<types extends Record<string, any>> = {
  [key in keyof types]: {
    bar?: types[key];
    foo?: (value:types[key])=>true;
  };
};

test2({
 key1:{
  bar: 2,
  foo: (input: number)=>true,
 },
 key2:{
  bar: 'hello', 
  foo: (input:number)=>true,// 未触发预期报错:input类型应为string
 }
})

失效原因

你新增的types泛型没有直接的推断来源,TypeScript无法从传入的dict参数反向推导出types的精确类型,只会将其放宽到约束上限Record<string, any>,此时dictionary2<types>中的types[key]会被推导为any,因此foo函数的入参类型校验完全失效。
同时TypeScript的泛型推断优先级会优先从实参推导dictionary泛型的实际类型,再去适配dictionary extends dictionary2<types>的约束,进一步导致types的类型被放宽来适配已推断出的dictionary类型,不会触发预期的校验。

解决方法

如果需要保留对dict参数的完整泛型引用,推荐使用单个泛型参数指代dict的类型,通过自约束完成类型校验:

type Dictionary2<D extends Record<string, { bar?: any }>> = {
  [K in keyof D]: {
    bar?: D[K]['bar'];
    foo?: (value: D[K]['bar']) => true;
  }
};

// 泛型D直接对应传入的dict的完整类型,满足你保留dict泛型引用的需求
function test2<D extends Record<string, { bar?: any }>>(dict: D extends Dictionary2<D> ? D : never) {
  // 函数内部可以直接使用D来拿到传入dict的精确类型
}

// 此时调用会正常触发预期报错
test2({
 key1:{
  bar: 2,
  foo: (input: number)=>true,
 },
 key2:{
  bar: 'hello', 
  foo: (input:number)=>true,// 报错:number类型不能赋值给string类型
 }
})

如果你确实需要单独提取每个key对应的bar值类型集合(也就是原来的types泛型),可以调整泛型推断优先级,让types优先从dict的bar属性推断:

function test2<T extends Record<string, any>, D extends dictionary2<T> = dictionary2<T>>(dict: D) {}

这种写法下TypeScript会优先从dict的bar属性推断T的精确类型,再约束D的类型,也能正常触发校验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 15:21:00