TypeScript如何定义返回类型依赖可选参数存在性的函数类型
解决方案
核心思路
你遇到的类型报错是因为TypeScript不会自动将(state: State, value?: string) => State | string类型的函数识别为符合重载定义的StateInteractor类型,我们可以通过封装一层通用构造工具来避免重复写重载代码。
第一步:定义基础类型和通用构造函数
先补全正确的类型定义,再写一个工具函数用来创建符合要求的Interactor:
// 你的State类型,根据实际业务调整 type State = { foo: string; other: string; }; // 你之前定义的重载函数类型 type StateInteractor = { (state: State): string; (state: State, value: string): State; }; // 通用构造工具,自动完成类型转换 const defineStateInteractor = ( impl: (state: State, value?: string) => State | string ): StateInteractor => impl as StateInteractor;
第二步:实现Interactor(支持普通函数/箭头函数,无需写重载)
// 箭头函数实现 const fooInteractor = defineStateInteractor((state, foo?: string) => { if (foo) { return { ...state, foo }; } return state.foo; }); // 普通函数实现也兼容 const anotherInteractor = defineStateInteractor(function(state, value?: string) { if (value) { return { ...state, foo: value.toUpperCase() }; } return state.foo.toLowerCase(); });
第三步:调用验证
完全符合你的业务使用要求,类型推导正常:
const state = { foo: "foo", other: "data" }; // 无参数调用返回string const val = fooInteractor(state); // 类型自动推导为string // 传参数调用返回State const newState = fooInteractor(state, "bar"); // 类型自动推导为State // 传入interact函数也正常 function interact(state: State, stateFn: StateInteractor) { const data: string = stateFn(state); const changedState: State = stateFn(state, data); } interact(state, fooInteractor);
进阶:通用多属性适配
如果需要针对State的不同属性创建同类Interactor,可以用泛型进一步封装,避免重复定义类型:
// 通用Interactor类型,T为状态类型,K为要操作的属性名 type GenericInteractor<T, K extends keyof T> = { (state: T): T[K]; (state: T, value: T[K]): T; }; // 通用构造器 const defineInteractor = <T, K extends keyof T>(_key: K) => { return ( impl: (state: T, value?: T[K]) => T | T[K] ): GenericInteractor<T, K> => impl as GenericInteractor<T, K>; }; // 为State的foo属性创建专属构造器 const defineFooInteractor = defineInteractor<State, "foo">("foo"); // 为State的other属性创建专属构造器 const defineOtherInteractor = defineInteractor<State, "other">("other"); // 实现other属性的Interactor const otherInteractor = defineOtherInteractor((state, value) => { if (value) return { ...state, other: value }; return state.other; });
这个方案本质是把重复的重载声明和类型断言逻辑收敛到了工具函数中,业务实现代码没有任何冗余,同时也完全保证类型安全。
内容的提问来源于stack exchange,提问作者SCdF
相关产品推荐
相关产品推荐

