深入理解Axios的TypeScript类型的约束

axios是一个非常流行的http请求库,而在typescript当中,使用泛型可以为axios的请求和响应去添加更为强大的类型约束。

什么是泛型?

  • 泛型 (Generics) 允许你编写可以适用于不同类型的代码,以增强代码的重用性和灵活性
  • 泛型可以在函数、类和接口中使用,它们可以用来定义参数类型、返回值类型或类成员的型。通过使用泛型,可以在不同的地方使用相同的逻辑和算法,但适用于不同类型的数据。
  • 泛型的基本语法是使用尖括号来表示一个类型参数,T 可以是任意合法的标识符,代表待确定的类型

那么如何使用typeScript当中的类型别名和泛型定义通用的axios请求类型,并且通过一个实例进行及用法的一个展示。

请求数据约束

1. 首先,新建一个目录,假设api,创建requestHandler.ts文件

2. 基础请求类型约束

import { AxiosResponse } from "axios";
 
type BaseRequest = (params?:T) => Promise>;

  type类型别名的一个定义,定义一个BaseRequest,将请求设置为一个泛型,分别T和V,T和V都是泛型类型中的一个约束。

        此时,T和V我们并不知道其数据类型是什么,至于BaseRequest它的本质应该是一个函数,这个函数将会传递一个参数params?(可选参数),类型为T。也就是请求类型与我们之前所设置的泛型当中的T类型是一一对应的。

        这个BaseRequest请求函数将会返回一个请求的结果内容(应为Promise),promise返回的具体内容为AxiosResponse结果内容,AxiosResponse内容也是一个泛型,它这个类型将会返回一个就是我们所设置的一个V的泛型内容。

        T:表示请求参数类型和我们函数中params的参数  T是一一对应的

        V:V表示响应类型,与函数返回的promise当中的AxiosResponse当中的V数据类型也是一一对应的。

3. 明确接口数据(获取到最终想要操作的todo信息内容):

深入理解Axios的TypeScript类型的约束_第1张图片

4. 进行具体的请求和响应类型的约束定义

我们定义了请求参数类型为GetTodoInfoParams   响应数据类型为TodoInfo

//请求参数类型
interface GetTodoInfoParams {
    id:number;
}
 
//响应数据类型(根据明确接口数据进行类型定义)
export interface TodoInfo {
    userId: number;
    id:number;
    title:string;
    completed: boolean;
}
 
//进行数据的一个获取   GetTodoInfoParams为参数  TodoInfo为返回的对象
export const getTodoInfo:BaseRquest = (
    params
) => {
    //请求的地址
    return axios.get(`https://jsonplaceholder.typicode.com/todos/${params?.id}`);
}

5.引入

import { TodoInfo,getTodoInfo } from '定义的文件路径'
import { useEffect,useState } from 'react'
 
const App = () => {
    //todo数据是数据请求之后数据返回的结果值
    const [todo,setTodo] = useState(null);  //联合数据类型 并且设置初始值为null
    useEffect(() => {
        //进行函数的请求操作
        //参数的传递
        getTodoInfo({id:12}).then((response) => {   //response 响应内容
                const todo: TodoInfo = response.data;
                setTodo(todo);
            })
            .catch((error) => {  //如遇到错误内容  则进行错误打印
                console.log(error); 
            });
    },[]);
}

6. 使用

{ todo?.title }

{ todo?.completed.toString() }

自动添加了?,为什么会有?,因为我们设置的是联合数据类型,所以会自动添加一个可选项?内容。

以上就是axios和typescript进行一个完美的结合,采用泛型和type类型进行一个整合,这时候,就会有一个强大的类型约束,当我们应用的时候,有非常安全的安全性和歧视性进行代码的一个协助操作,帮助我们开发人员能够提高一个更好的编程和代码的可读性,能够让我们的项目变得更为得健壮。

响应失败数据约束

那么,除了 BaseRequest 基础请求之外,我们是不是还有对应的响应操作,而响应过程中,除了success成功,是不是还可能涉及到error错误失败的处理呢,所以我们可以进行一个进一步的类型声明约束操作?

1. 成功约束

type SuccessResponse = {
    code:"success";
    data:V
}

那么设置泛型仍旧为V,为什么是V呢?因为成功以后data数据就应该是我们请求时约定的数据类型。

2. 失败约束

失败操作是不是也需要定义类型限制呢,我们定义了一个E,并设置默认值AxiosError

type ErrorResponse = {
    code: 'error';
    error: E;
} 

那么我们现在已设置了成功的响应内容和失败的响应内容,那么现在就可以定义基础的响应内容。

3.基础响应类型约束( 这个内容既可能是成功的,也可能是错误的):

type BaseResponse(V,E) = Promise | ErrorResponse>;

4. 请求函数定义(此函数会返回一个函数(高阶函数))

高阶函数:函数的参数可以是函数;而函数的返回值可以是函数

export const requestHandler =
    // 对高阶函数设置类型约束
    (request: BaseRequest) =>  
    async (params?: T): BaseResponse => {
        try{
            const response = await request(params);
            return {
                code:"success",
                data: response.data,
            };
        } catch (e) {
            return {
                code: "error",
                error: e as E,
        };
    }
}
I

5. 在 api 目录下新建一个 todos.ts 文件(对 requestHandler.ts 文件进行剪切)

requestHandler.ts 文件:

只需要确认有 BaseRequest、 BaseResponse 数据类型的声明就可以了

import {  AxiosError,AxiosResponse } from "axios";
 
// 基础请求类型约束
type BaseRequest = (params?:T) => Promise>;

// 成功约束
type SuccessResponse = {
    code:"success";
    data:V
}

// 失败约束
type ErrorResponse = {
    code: 'error';
    error: E;
} 

// 基础响应类型约束
type BaseResponse(V,E) = Promise | ErrorResponse>;

// 请求函数定义
export const requestHandler =
    // 对高阶函数设置类型约束
    (request: BaseRequest) =>  
    async (params?: T): BaseResponse => {
        try{
            const response = await request(params);
            return {
                code:"success",
                data: response.data,
            };
        } catch (e) {
            return {
                code: "error",
                error: e as E,
        };
    }
}

todos.ts 文件:

进行 axios 和 requestHandler 方法的引入,对之前在requestHandler.ts 文件剪切的代码进行复制粘贴

import axios from "axios";
import { requestHandler } from "./requestHandler";

//请求参数类型
interface GetTodoInfoParams {
    id:number;
}
 
//响应数据类型(根据明确接口数据进行类型定义)
export interface TodoInfo {
    userId: number;
    id:number;
    title:string;
    completed: boolean;
}
 
//进行数据的一个获取   GetTodoInfoParams为参数  TodoInfo为返回的对象
export const getTodoInfo = requestHandler(
    (params) => {
        return axios.get(
            `https://jsonplaceholder.typicode.com/todos/${params?.id}`
        );
    }
);

6. 引入

import { TodoInfo,getTodoInfo } from './api/todos';
import { useEffect,useState } from 'react'
 
const App = () => {
    //todo数据是数据请求之后数据返回的结果值
    const [todo,setTodo] = useState(null);  //联合数据类型 并且设置初始值为null
    
    async function getTodo(){
        const todoReponse = await getTodoInfo({id:12})
        if(todoReponse.code === "error"){
           console.log(todoReponse.error.message)
        } else {
           setTodo(todoReponse.data);
        }
    }
    useEffect(() => {
       getTodo()
    },[]);
}

现在,我们已经对axios进一步更为深入的 TypeScript 的结合操作,主要是设置成功、错误以及基础响应的内容其数据类型的一个约束,并且利用了是一个高阶函数,而 requestHandler 高阶函数将会接收到一个参数,而这个参数是一个函数,那么最终这个高阶函数还会返回一个结果值,这个结果值就是我们所谓的BaseRequest,它即可能会包含 SuccessResponse 也可能会包含 ErrorResponse,也就是成功或错误,那么,我们在真正的进行一个函数的数据类型确认的时候就可以明确其泛型的内容 以及 参数的设定 和 返回值的设定。

那么,在组件当中,进行一个具体的调用的时候,非常的明确的查看到我们对应的代码提示包括code码 以及 data数据 或者是 error 的一个提升信息以及error下面的消息内容。

你可能感兴趣的:(typescript,javascript,前端)