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

如何让TypeScript在函数体内识别参数及解构对象属性的关联?

如何让TypeScript在函数体内理解解构对象参数的两个属性之间的关联?

我尝试了两种写法来限制函数参数的合法性,但函数内部始终无法正确推断两个属性的关联类型:

type Type<T extends string | number> = {
  one: T;
  two: T extends string ? number : string;
};
function foo<T extends string | number>({ one, two }: Type<T>) {
  if (typeof one === "string") {
    two; // 这里无法推断two是number类型
  } else {
    two; // 这里无法推断two是string类型
  }
}

foo({one: 'one', two: 'two'}) // 调用时报错,符合预期
foo({one: 'one', two: 2}) // 合法调用

function bar({ one, two }: { one: string; two: number }): void;
function bar({ one, two }: { one: number; two: string }): void;
function bar<T extends string | number>({
  one,
  two,
}: {
  one: string | number;
  two: string | number;
}): void {
  if (typeof one === "string") {
    two; // 同样无法推断two的类型
  } else {
    two; // 同样无法推断two的类型
  }
}

bar({one: 'one', two: 'two'}) // 调用时报错,符合预期
bar({one: 'one', two: 2}) // 合法调用

解决方法

问题出在解构后变量丢失了原对象的类型关联,TypeScript无法单独跟踪one和two之间的约束关系。以下是几种可行的修复方式:

1. 保留完整的参数对象,避免解构

通过访问原对象的属性,TypeScript可以基于one的类型窄化整个对象的类型,从而正确推断two的类型:

type Type<T extends string | number> = {
  one: T;
  two: T extends string ? number : string;
};
function foo<T extends string | number>(param: Type<T>) {
  if (typeof param.one === "string") {
    param.two; // 此时TypeScript能准确推断出two是number类型
  } else {
    param.two; // 此时TypeScript能准确推断出two是string类型
  }
}

foo({one: 'one', two: 2}) // 合法
foo({one: 'one', two: 'two'}) // 类型错误,符合预期

2. 使用联合类型定义参数,配合对象窄化

直接把参数定义为合法类型的联合,函数内部通过判断one的类型来窄化整个参数的类型:

type ValidParams = 
  | { one: string; two: number }
  | { one: number; two: string };

function baz(param: ValidParams) {
  if (typeof param.one === "string") {
    param.two; // 自动推断为number类型
  } else {
    param.two; // 自动推断为string类型
  }
}

baz({one: 'one', two: 2}) // 合法
baz({one: 1, two: 'two'}) // 合法
baz({one: 'one', two: 'two'}) // 类型错误,符合预期

3. 自定义类型守卫(适合必须解构的场景)

如果必须解构变量,可以用自定义类型守卫手动关联one和two的类型:

// 自定义类型守卫,声明当one是string时,two必然是number
function isStringOne(
  one: string | number,
  two: string | number
): one is string {
  return typeof one === "string";
}

function bar({ one, two }: { one: string; two: number }): void;
function bar({ one, two }: { one: number; two: string }): void;
function bar({ one, two }: { one: string | number; two: string | number }): void {
  if (isStringOne(one, two)) {
    two satisfies number; // 此时two被推断为number类型
  } else {
    two satisfies string; // 此时two被推断为string类型
  }
}

bar({one: 'one', two: 2}) // 合法
bar({one: 'one', two: 'two'}) // 类型错误,符合预期

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 21:29:52