如何基于可选属性推断TypeScript函数的返回类型?
问题背景
先通过简化示例说明核心需求:
type Mapper<T, R> = (data: T) => R; interface Config<T, R> { readonly mapper?: Mapper<T, R>; } function transform<T, R>(config: Config<T, R>, data: T) { return config.mapper?.(data) ?? data; } const mapper: Mapper<number, string> = (data: number) => `${data};` const result1 = transform({}, 1); // 期望result1类型为number(未传mapper) const result2 = transform({ mapper }, 1); // 期望result2类型为string(传入mapper)
需要为transform函数正确标注返回类型,该函数仅为简化示例,用于引出实际业务问题。
实际业务场景
现有状态类型与映射函数定义如下:
export type PendingState = { type: "PENDING"; }; export type SuccessState<T> = { type: "SUCCESS"; data: T; }; export type ErrorState = { type: "ERROR"; error: unknown; }; export type SuspenseState<T> = PendingState | SuccessState<T> | ErrorState; export type PendingStateMapper<R> = () => R; export type SuccessStateMapper<T, R> = (data: T) => R; export type ErrorStateMapper<R> = (error: unknown) => R; export interface Mappers<T, P, S, E> { readonly pendingState?: PendingStateMapper<P>; readonly successState: SuccessStateMapper<T, S>; readonly errorState: ErrorStateMapper<E>; }
当前通过函数重载实现返回类型推断:
export function fromSuspenseState<T, P, S, E>(mappers: Mappers<T, P, S, E> & { pendingState: PendingStateMapper<P> }): OperatorFunction<SuspenseState<T>, P | S | E>; export function fromSuspenseState<T, P, S, E>(mappers: Mappers<T, P, S, E> & { pendingState?: undefined }): OperatorFunction<SuspenseState<T>, null | S | E>; export function fromSuspenseState<T, P, S, E>(mappers: Mappers<T, P, S, E>): OperatorFunction<SuspenseState<T>, P | S | E | null> { return (source$: Observable<SuspenseState<T>>): Observable<P | S | E | null> => { return source$.pipe( map((state) => { switch (state.type) { case "PENDING": return mappers.pendingState ? mappers.pendingState() : null; case "SUCCESS": return mappers.successState(state.data); case "ERROR": return mappers.errorState(state.error); } }) ); }; }
传入PendingStateMapper时返回P,否则返回null。
现需将SuccessStateMapper和ErrorStateMapper也设为可选:
- 传入
SuccessStateMapper时返回S,否则返回T; - 传入
ErrorStateMapper时返回E,否则返回unknown。
此时函数重载需要大量签名,维护成本极高。
尝试与最终方案
尝试通过条件类型推断未成功,最终实现了可行方案:
type PendingStateMapperResult<T, P, S, E, M extends Mappers<T, P, S, E>> = M["pendingState"] extends PendingStateMapper<infer R> ? R : null; type SuccessStateMapperResult<T, P, S, E, M extends Mappers<T, P, S, E>> = M["successState"] extends SuccessStateMapper<T, infer R> ? R : T; type ErrorStateMapperResult<T, P, S, E, M extends Mappers<T, P, S, E>> = M["errorState"] extends ErrorStateMapper<infer R> ? R : unknown; export type FromSuspenseStateResult<T, P, S, E, M extends Mappers<T, P, S, E>> = | PendingStateMapperResult<T, P, S, E, M> | SuccessStateMapperResult<T, P, S, E, M> | ErrorStateMapperResult<T, P, S, E, M>; export function fromSuspenseState<T, P, S, E, M extends Mappers<T, P, S, E>>(mappers: M): OperatorFunction<SuspenseState<T>, FromSuspenseStateResult<T, P, S, E, M>> { return (source$: Observable<SuspenseState<T>>): Observable<FromSuspenseStateResult<T, P, S, E, M>> => { return source$.pipe( map((state) => { switch (state.type) { case "PENDING": return (mappers.pendingState?.() ?? null) as PendingStateMapperResult<T, P, S, E, M>; case "SUCCESS": return (mappers.successState?.(state.data) ?? state.data) as SuccessStateMapperResult<T, P, S, E, M>; case "ERROR": return (mappers.errorState?.(state.error) ?? state.error) as ErrorStateMapperResult<T, P, S, E, M>; } }) ); }; }
现寻求基于参数属性推断返回类型的通用经验或准则,希望有经验者分享解决此类问题的思路。
内容的提问来源于stack exchange,提问作者lukmac
相关产品推荐
相关产品推荐

