打字稿中的可选泛型

Optional Generics in typescript

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

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;
        }
    },
};

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

我想知道是否可以使用它,所以如果两种类型都用于 post 函数,它将使用第二种类型作为 return 类型或使用第一种类型作为return 类型?

可以粘贴到 typescript playground 的完整示例,并在出现错误的地方添加注释

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);
})();

根据给出的示例,我可能会将 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;
        }
    },
};

(我将 K 更改为 U,因为名称 K 通常暗示可分配给 keyof any 的类似键的属性)。这里 return 类型将只是 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 缺乏对 partial type parameter inference, so there's no way to just have the compiler infer T properly if you'd also like to specify U explicitly, and 的直接支持并不一定比您自己手动指定 T 更好。

总之,希望对您有所帮助;祝你好运!

Playground link to code