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

TypeScript条件类型回调调用需传入交叉类型参数的问题

TypeScript 回调参数类型匹配问题

问题背景

需要实现一个函数,入参里的isArray参数决定了回调函数的参数是单个Option对象还是Option数组。尝试了两种类型定义方式后,函数内部调用回调时出现类型不匹配错误——TypeScript要求传入Option & Option[]交叉类型的参数,用类型断言能解决但不够优雅。

初始泛型类型实现(存在类型错误)

type Option = {
  name: string
  value: string
}

type FunctionProps<IsArray extends boolean | undefined> = {
  isArray?: IsArray
  callback: IsArray extends false
    ? (options: Option) => void
    : (options: Option[]) => void
}

const func = <T extends boolean | undefined = false>({isArray, callback}: FunctionProps<T>) => {
  const options: Option[] = /* 合法的Option数组值 */
  const currentOption: Option = /* 合法的单个Option值 */

  if (isArray) {
    callback(options)  // 错误:Argument of type 'Option[]' is not assignable to parameter of type 'Option & Option[]'.
  } else {
    callback(currentOption)  // 错误:Argument of type 'Option' is not assignable to parameter of type 'Option & Option[]'.
  }
}

联合类型尝试(未解决问题)

type FunctionProps = {
  isArray: false
  callback: (options: Option) => void
} | {
  isArray: true
  callback: (options: Option[]) => void
}

解决方案

问题核心是TypeScript无法在函数内部自动根据isArray的值窄化callback的类型。以下是几种更优雅的解决方式:

方案1:可辨识联合类型 + 类型断言

补充联合类型中isArray未传的情况,在分支中用类型断言明确当前callback的类型:

type Option = {
  name: string
  value: string
}

type FunctionProps = 
  | { isArray: true; callback: (options: Option[]) => void }
  | { isArray: false; callback: (options: Option) => void }
  | { isArray?: undefined; callback: (options: Option) => void };

const func = (props: FunctionProps) => {
  const options: Option[] = [{ name: "test", value: "1" }];
  const currentOption: Option = { name: "single", value: "2" };

  if (props.isArray) {
    (props as typeof props & { isArray: true }).callback(options);
  } else {
    (props as typeof props & { isArray?: false | undefined }).callback(currentOption);
  }
};

方案2:类型守卫函数

自定义类型守卫函数,让TypeScript能自动识别分支中的参数类型:

type Option = {
  name: string
  value: string
}

type ArrayProps = { isArray: true; callback: (options: Option[]) => void };
type NonArrayProps = { isArray?: false | undefined; callback: (options: Option) => void };
type FunctionProps = ArrayProps | NonArrayProps;

// 类型守卫:判断是否为ArrayProps类型
function isArrayProps(props: FunctionProps): props is ArrayProps {
  return props.isArray === true;
}

const func = (props: FunctionProps) => {
  const options: Option[] = [{ name: "test", value: "1" }];
  const currentOption: Option = { name: "single", value: "2" };

  if (isArrayProps(props)) {
    props.callback(options); // TypeScript自动识别为数组类型的回调
  } else {
    props.callback(currentOption); // TypeScript自动识别为单个对象类型的回调
  }
};

方案3:函数重载

用函数重载明确不同参数组合对应的回调类型,实现逻辑更直观:

type Option = {
  name: string
  value: string
}

// 重载定义:明确不同入参对应的回调类型
function func(props: { isArray: true; callback: (options: Option[]) => void }): void;
function func(props: { isArray?: false | undefined; callback: (options: Option) => void }): void;

// 函数实现
function func(props: { isArray?: boolean; callback: ((options: Option) => void) | ((options: Option[]) => void) }) {
  const options: Option[] = [{ name: "test", value: "1" }];
  const currentOption: Option = { name: "single", value: "2" };

  if (props.isArray) {
    (props.callback as (options: Option[]) => void)(options);
  } else {
    (props.callback as (options: Option) => void)(currentOption);
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 00:10:47