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
相关产品推荐
相关产品推荐

