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

如何在TypeScript函数返回值中正确使用判别式联合

问题:TypeScript中如何优化判别式联合在函数返回值中的使用

我是TypeScript新手,想了解如何在函数返回值中运用判别式联合。我有一个调用两个接口的async函数,希望根据每个API的调用结果为返回值正确标注类型。

目前已定义以下类型:

interface GetDetailSuccess {
  status: "success";
  data: MovieDetailResult;
}

interface GetDetailFail {
  status: "failed";
  error: any;
}

interface GetCastSuccess {
  status: "success";
  data: MovieCastResult
}

interface GetCastFail {
  status: "failed";
  error: any;
}

type MovieDetail = GetDetailSuccess | GetDetailFail;
type MovieCast = GetCastSuccess | GetCastFail;

type ReturnValue = {
  movieDetail: MovieDetail;
  movieCast: MovieCast;
};

简化版函数代码:

export const getMovieDetailAndCast = async ():Promise<ReturnValue> => {

    const movDet = {} as MovieDetail;
    const movCas = {} as MovieCast;
  
    await Promise.allSettled([
      api.getMovieDetail(),
      api.getMovieCast(),
    ])
      .then((responses) => {
        responses.forEach((res, index) => {
          if (index === 0) {
            if (res.status === "fulfilled") {
              movDet.status = "success";
              if (movDet.status === "success") {
                movDet.data = res.value.data;
              }
            }
  
            if (res.status === "rejected") {
              movDet.status = "failed";
              if (movDet.status === "failed") {
                movDet.error = res.reason.response.data.status_message;
              }
            }
          }
  
          if (index === 1) {
            if (res.status === "fulfilled") {
              movCas.status = "success";
              if (movCas.status === "success") {
                movCas.data = res.value.data;
              }
            }
  
            if (res.status === "rejected") {
              movCas.status = "failed";
              if (movCas.status === "failed") {
                movCas.error = res.reason.response.data.status_message;
              }
            }
          }
        });
      })
      .catch((err) => {
        console.error(err);
      });
  
    return {
        movieDetail: movDet,
        movieCast: movCas,
    };
}

目前IDE没有报错,但不确定这种写法是否正确,尤其是类型收窄的部分,以及使用as断言空对象的操作。请问可以如何优化上述代码?


优化方案

1. 移除不安全的空对象断言

用{} as MovieDetail是空对象强制断言为联合类型,本质上不符合类型结构(空对象既没有status也没有data/error),属于不安全操作。应该直接根据API结果创建对应类型的完整对象。

2. 简化冗余的类型收窄逻辑

设置movDet.status = "success"后,TypeScript会自动将movDet的类型收窄为GetDetailSuccess,不需要额外加if (movDet.status === "success")判断,这部分是冗余代码。

3. 抽离通用逻辑,提升可读性

把单个API结果的处理逻辑抽成独立函数,避免在forEach中写大量分支判断,代码结构更清晰。

4. 统一使用async/await语法

混用await和.then/.catch会让代码逻辑割裂,统一用async/await更符合异步代码的可读性要求。

优化后的完整代码

// 抽离通用API结果处理函数
const handleApiResponse = <T>(
  result: PromiseSettledResult<{ data: T }>
): { status: "success"; data: T } | { status: "failed"; error: any } => {
  if (result.status === "fulfilled") {
    return { status: "success", data: result.value.data };
  }
  return { status: "failed", error: result.reason.response.data.status_message };
};

export const getMovieDetailAndCast = async (): Promise<ReturnValue> => {
  // 直接获取所有API的settled结果
  const [detailRes, castRes] = await Promise.allSettled([
    api.getMovieDetail(),
    api.getMovieCast(),
  ]);

  // 处理结果并直接生成符合类型的对象
  const movieDetail = handleApiResponse<MovieDetailResult>(detailRes) as MovieDetail;
  const movieCast = handleApiResponse<MovieCastResult>(castRes) as MovieCast;

  return { movieDetail, movieCast };
};

可选优化:明确错误类型

把error: any替换为具体的错误接口,让类型更严谨:

interface ApiError {
  status_message: string;
  // 可以添加其他错误字段,比如状态码等
}

// 更新失败类型定义
interface GetDetailFail {
  status: "failed";
  error: ApiError;
}

interface GetCastFail {
  status: "failed";
  error: ApiError;
}

优化后的代码既符合判别式联合的类型要求,TypeScript能通过status字段准确收窄类型,又避免了不安全的类型断言,代码可读性和可维护性都大幅提升。

内容的提问来源于stack exchange,提问作者chetmanleyy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 01:55:18