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

如何让TypeScript根据判别式参数正确推断其他函数参数?

实现TypeScript参数关联类型推断

先看你给出的原始代码问题:

type ATrue = (a: true, b: number) => void;
type AFalse = (a: false, b: string) => void;

const fromUnion: ATrue | AFalse = (a, b) => {
  if (a) {
    b; // any
  } else {
    b; // any
  }
};

const fromIntersection: ATrue & AFalse = (a, b) => {
  if (a) {
    b; // number | string
  } else {
    b; // number | string
  }
};

当前TypeScript的推断结果如注释所示:fromUnion中b被推断为any,fromIntersection中b被推断为number | string,无法根据a的布尔值自动关联b的类型。

解决方案

1. 使用函数重载(最直观方式)

函数重载可以明确声明不同参数组合对应的类型,TypeScript能正确根据a的值窄化b的类型:

// 重载签名:定义不同参数组合的类型约束
function handleArgs(a: true, b: number): void;
function handleArgs(a: false, b: string): void;
// 实现签名:编写函数逻辑
function handleArgs(a: boolean, b: number | string): void {
  if (a) {
    b; // 类型为number,可安全调用number方法如toFixed
    console.log(b.toFixed(2));
  } else {
    b; // 类型为string,可安全调用string方法如toLowerCase
    console.log(b.toLowerCase());
  }
}

2. 泛型结合条件类型

通过泛型约束和条件类型,让b的类型完全依赖于a的布尔值:

type ConditionalFn<T extends boolean> = (
  a: T,
  b: T extends true ? number : string
) => void;

const handleArgs: ConditionalFn<boolean> = (a, b) => {
  if (a) {
    b; // number
  } else {
    b; // string
  }
};

3. 基于原有类型构建区分联合参数

如果需要保留ATrue和AFalse的定义,可以提取它们的参数类型组成区分联合类型,再用于函数定义:

type ATrue = (a: true, b: number) => void;
type AFalse = (a: false, b: string) => void;

// 提取两个函数的参数类型,组成区分联合
type ArgsUnion = Parameters<ATrue> | Parameters<AFalse>;

const handleArgs: (...args: ArgsUnion) => void = (a, b) => {
  if (a) {
    b; // number
  } else {
    b; // string
  }
};

为什么原有方式不行?

  • 函数联合类型:TypeScript对函数联合的参数处理遵循逆变原则,要求传入的参数能满足所有联合分支的参数要求,因此内部无法通过a的值窄化b的类型,只能推断为any。
  • 函数交叉类型:交叉后的函数要求参数同时满足两个原始函数的参数,a的类型会被推断为true & false(即never),b则是number | string,自然无法区分类型。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 09:53:00