解决TypeScript函数基于第二个可选参数的第一个参数类型推导问题
解决方案
问题根源在于原类型定义中,泛型Selected会被update参数的类型自动推断。当传入异步更新函数时,Selected会被推断为Promise<number>,但选择器函数返回的是原始number类型,导致类型不兼容。
修改类型定义(使用函数重载)
通过函数重载明确每种更新方式对应的类型约束,确保选择器始终返回原始状态类型,而非Promise:
type NestedStateSetter<State> = { <Selected = State>(update: Selected, selector?: (state: State) => Selected): Promise<Selected>; <Selected = State>(update: () => Selected, selector?: (state: State) => Selected): Promise<Selected>; <Selected = State>(update: () => Promise<Selected>, selector?: (state: State) => Selected): Promise<Selected>; }; const initialState = { a: { b: { c: 0, }, }, }; const setState: NestedStateSetter<typeof initialState> = (update, selector) => { throw "Yeet"; }; setState(1, (state) => state.a.b.c) // Ok setState(() => 2, (state) => state.a.b.c) // Ok setState(async () => 5, (state) => state.a.b.c) // Now Ok
原理说明
函数重载分别定义了三种更新场景的类型:
- 直接传入值:
update为Selected类型,选择器返回Selected - 同步更新函数:
update返回Selected,选择器返回Selected - 异步更新函数:
update返回Promise<Selected>,选择器仍返回Selected
这样TypeScript会正确推断Selected为选择器返回的原始类型(如示例中的number),而非异步函数返回的Promise类型,解决了类型不匹配问题,同时避免了柯里化带来的破坏性变更。
内容的提问来源于stack exchange,提问作者Gabriel Pureliani
相关产品推荐
相关产品推荐

