You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于可选属性推断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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 21:37:50