首页 > 解决方案 > 打字稿中的可选泛型

问题描述

所以我有一个对strapi服务器的api调用的包装器

export const api = {
    post: async<T extends unknown, K>(url: string, body: Partial<T>, jwt?: string): Promise<K> => {
        try {
            const result = await postData<Partial<T>, K>(url, body, jwt);
            return result;
        } catch (e) {
            throw e;
        }
    },
};

我正在尝试获取它,因此 K 是可选的,因此我可以执行以下操作

 await api.post<type1, type2>(url, body);
 await api.post<type1>(url, body);

我试过了

export const api = {
    post: async<T extends unknown, K = undefined>(url: string, body: Partial<T>, jwt?: string): Promise<K | T> => {
        try {
            const result = await postData<Partial<T>, K | T>(url, body, jwt);
            return result;
        } catch (e) {
            throw e;
        }
    },
};

但是我会得到输入错误,因为当返回类型应该只是 type2 时它会丢失 type1 中的一个字段,或者我会得到返回对象可能未定义。

我想知道是否有可能拥有它,所以如果两种类型都用于 post 函数,它将使用第二种类型作为返回类型还是使用第一种类型作为返回类型?

可以粘贴到打字稿游乐场的完整示例,其中包含发生错误的注释

const api = {
    post: async<T extends unknown, K = undefined>(url: string, body: Partial<T>, jwt?: string): Promise<K | T> => {
        try {
            const result = await postData<Partial<T>, K | T>(url, body, jwt);
            return result;
        } catch (e) {
            throw e;
        }
    },
};

function postData<K, T>(url: string, data: K, jwt: string = '', failOnNotOk: boolean = true): T {
    const request: T = (data) as any;

    return request;
}

type user = {
    email: string;
    password: string;
}

type res = {
    valid: string;
}
(async () => {
    const url: string = 'https://google.com';
    const body: user = {
        email: 'test@example.com',
        password: 'test1234',
    };
    // this gives an error about result having the possibility of being undefined
    const result = await api.post<user>(url, body);
    console.log(result.email);

    // returns an errror about valid not being a field on user when the return type should only be res
    const res = await api.post<user, res>(url, body);
    console.log(res.valid);
})();

标签: typescripttypescript-generics

解决方案


使用给出的示例,我可能会更改api.post为:

const api = {
    post: async<T extends unknown, U = T>(
      url: string, 
      body: Partial<T>, 
      jwt?: string
    ): Promise<U> => {
        try {
            const result = await postData<Partial<T>, U>(url, body, jwt);
            return result;
        } catch (e) {
            throw e;
        }
    },
};

(我改成KU因为这个名字K通常暗示着可以分配给 的类似键的属性keyof any)。这里的返回类型将只是,如果没有指定Promise<U>U将默认为。T这给出了以下行为:

const result = await api.post<user>(url, body);
console.log(result.email); // okay
const res = await api.post<user, res>(url, body);
console.log(res.valid); // okay

我想你想要的。user请注意,需要显式指定而不是让编译器从 的类型推断它有点烦人body,但如果你不介意这样做,那很好。TypeScript 缺乏对部分类型参数推断的直接支持,因此T如果您还想U显式指定,则无法让编译器正确推断,而且我所知道的解决方法不一定比手动指定更好T

无论如何,希望有所帮助;祝你好运!

Playground 代码链接


推荐阅读