如何让封装的Redux useSelector Hook的泛型R自动从回调返回值推导类型?
如何让封装的Redux useSelector Hook的泛型R自动从回调返回值推导类型?
当然可以实现!你现在的问题出在泛型参数的定义上——原来的代码把R作为一个需要显式指定的泛型参数,但实际上我们可以让TypeScript自动从你传入的selector回调的返回值里推断出R的类型,完全不用手动写。
具体修改方案
我们只需要调整useAppSelector的泛型定义,去掉显式的R参数,让TypeScript自动推导selector的返回类型就行。下面是两种可行的修改方式:
方式1:利用ReturnType自动推断返回类型
export const useAppSelector = <T extends AbstractContract>( // 不用显式声明R,TypeScript会自动从selector的返回值推断 selector: (container?: ContractContainer<T>) => unknown, equalFnOptions?: EqualityFn<unknown> ): ReturnType<typeof selector> => { return useSelector<AppState<T>, ReturnType<typeof selector>>((state) => { if (state.data.activeObject) { const container = getContainerFromCache( state.data.contractCache, state.data.activeContract ); // 用ReturnType断言类型,确保和selector返回值匹配 return selector(container) as ReturnType<typeof selector>; } // 当没有activeObject时,返回符合selector返回类型的默认值 return undefined as ReturnType<typeof selector>; }, equalFnOptions as EqualityFn<ReturnType<typeof selector>>); };
方式2:让R从selector参数自动推导
export const useAppSelector = <T extends AbstractContract, R>( selector: (container: ContractContainer<T>) => R, equalFnOptions?: EqualityFn<R | undefined> ): R | undefined => { return useSelector<AppState<T>, R | undefined>((state) => { if (state.data.activeObject) { const container = getContainerFromCache( state.data.contractCache, state.data.activeContract ); // 确保container存在时才调用selector,避免undefined报错 return container ? selector(container) : undefined; } return undefined; }, equalFnOptions); };
调用方式不变,类型自动生效
修改完Hook之后,你原来的调用代码完全不用改,TypeScript会自动帮你推断出owner的类型:
type CarContract = { id: number; owner: Person; } const owner = useAppSelector<CarContract>( (container) => container.contract.owner ); // 现在owner的类型会被自动推断为Person(或Person | undefined,取决于你是否处理了container为undefined的情况)
为什么这样能行?
原来的代码里,R是作为独立的泛型参数需要手动指定的,但调整后,R会被TypeScript从selector回调的返回值里自动推导出来——当你传入<CarContract>时,TypeScript先确定container的类型是ContractContainer<CarContract>,再结合你写的container.contract.owner,就能直接推断出返回值是Person类型。
如果你的selector需要处理container可能为undefined的情况,比如用可选链container?.contract.owner,那TypeScript也会自动把owner的类型推断为Person | undefined,非常贴合实际场景。
内容来源于stack exchange
相关产品推荐
相关产品推荐

