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

如何用TypeScript结合Axios实现强类型REST客户端?

基于WorkoutLibrary接口的Axios实现示例

前置准备

  1. 安装Axios依赖:
npm install axios
  1. 补充定义接口中用到的辅助类型(需根据实际API结构调整):
// 统一错误响应类型
export interface ErrorResponse {
  code: number;
  message: string;
}

// 获取训练列表的入参
export interface GetWorkoutListOptions {
  page?: number;
  limit?: number;
}

// 获取训练列表的成功响应
export interface GetWorkoutList200Response {
  workouts: Array<{ id: string; name: string; duration: number }>;
  total: number;
}

// 创建训练的入参
export interface CreateWorkoutOptions {
  name: string;
  duration: number;
  exercises: Array<string>;
}

// 创建训练的成功响应
export interface CreateWorkout201Response {
  id: string;
  name: string;
  createdAt: string;
}

// 更新训练的入参
export interface UpdateWorkoutOptions {
  id: string;
  name?: string;
  duration?: number;
}

// 更新训练的成功响应
export interface UpdateWorkout200Response {
  id: string;
  name: string;
  updatedAt: string;
}

// 获取单个训练的成功响应
export interface GetWorkout200Response {
  id: string;
  name: string;
  duration: number;
  exercises: Array<string>;
}

// 删除训练的入参
export interface DeleteWorkoutOptions {
  workoutId: string;
}

// 删除训练的成功响应
export interface DeleteWorkout200Response {
  success: boolean;
  message: string;
}

// 你的原始接口(修正了get方法的入参类型错误)
export interface WorkoutLibrary {
  "/Workout": {
      get: (input?: GetWorkoutListOptions) => Promise<GetWorkoutList200Response | ErrorResponse>;
      post: (input: CreateWorkoutOptions) => Promise<CreateWorkout201Response | ErrorResponse>;
      put: (input: UpdateWorkoutOptions) => Promise<UpdateWorkout200Response | ErrorResponse>;
  };
  "/workout/{workoutId}": {
      get: (input?: { workoutId: string }) => Promise<GetWorkout200Response | ErrorResponse>;
      delete: (input?: DeleteWorkoutOptions) => Promise<DeleteWorkout200Response | ErrorResponse>;
  };
}

实现WorkoutApiService类

import axios, { AxiosError } from 'axios';

export class WorkoutApiService implements WorkoutLibrary {
  // 基础API域名,根据实际情况修改
  private baseUrl = 'https://your-api-domain.com/api';

  // 通用请求封装,统一处理错误
  private async request<T>(config: Parameters<typeof axios.request>[0]): Promise<T | ErrorResponse> {
    try {
      const response = await axios.request<T>(config);
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error)) {
        const axiosError = error as AxiosError<ErrorResponse>;
        return {
          code: axiosError.response?.status || 500,
          message: axiosError.response?.data.message || axiosError.message || '请求失败'
        };
      }
      return { code: 500, message: '未知错误' };
    }
  }

  // 实现"/Workout"下的所有方法
  "/Workout": {
    get: async (input?: GetWorkoutListOptions) => {
      return this.request<GetWorkoutList200Response>({
        method: 'GET',
        url: `${this.baseUrl}/Workout`,
        params: input
      });
    },

    post: async (input: CreateWorkoutOptions) => {
      return this.request<CreateWorkout201Response>({
        method: 'POST',
        url: `${this.baseUrl}/Workout`,
        data: input
      });
    },

    put: async (input: UpdateWorkoutOptions) => {
      return this.request<UpdateWorkout200Response>({
        method: 'PUT',
        url: `${this.baseUrl}/Workout`,
        data: input
      });
    }
  };

  // 实现"/workout/{workoutId}"下的所有方法
  "/workout/{workoutId}": {
    get: async (input?: { workoutId: string }) => {
      if (!input?.workoutId) {
        return { code: 400, message: 'workoutId 必填' };
      }
      const url = `${this.baseUrl}/workout/${input.workoutId}`;
      return this.request<GetWorkout200Response>({
        method: 'GET',
        url
      });
    },

    delete: async (input?: DeleteWorkoutOptions) => {
      if (!input?.workoutId) {
        return { code: 400, message: 'workoutId 必填' };
      }
      const url = `${this.baseUrl}/workout/${input.workoutId}`;
      return this.request<DeleteWorkout200Response>({
        method: 'DELETE',
        url
      });
    }
  };
}

使用示例

// 初始化服务实例
const workoutService = new WorkoutApiService();

// 获取训练列表
async function fetchWorkouts() {
  const result = await workoutService["/Workout"].get({ page: 1, limit: 10 });
  if ('code' in result) {
    console.error('获取列表失败:', result.message);
  } else {
    console.log('训练列表:', result.workouts);
  }
}

// 创建新训练
async function addWorkout() {
  const result = await workoutService["/Workout"].post({
    name: '上肢力量训练',
    duration: 45,
    exercises: ['俯卧撑', '引体向上']
  });
  if ('code' in result) {
    console.error('创建失败:', result.message);
  } else {
    console.log('创建成功,训练ID:', result.id);
  }
}

// 获取单个训练详情
async function fetchWorkoutDetail() {
  const result = await workoutService["/workout/{workoutId}"].get({ workoutId: '123' });
  if ('code' in result) {
    console.error('获取详情失败:', result.message);
  } else {
    console.log('训练详情:', result);
  }
}

核心概念指引

  • TypeScript接口契约:WorkoutLibrary定义了API服务的方法、入参和返回值规范,强制实现类遵循规则,避免类型错误。
  • Axios通用封装:request方法统一处理请求逻辑和错误捕获,减少重复代码,同时将Axios错误转换为统一格式,方便上层处理。
  • 路径参数替换:对于带占位符的路径,需要将{workoutId}替换为实际参数值,确保请求URL正确。
  • 联合类型窄化:通过'code' in result判断返回值是成功响应还是错误响应,这是TypeScript区分联合类型的常用技巧。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 09:43:09