是否有可能 DRY up overloaded function a signature which uses generics?

问题描述 投票:0回答:1

我正在编写一个简单的 Axios 包装函数,它结合了 zod-parsing 并返回一个可区分的联合,以实现更愉快的错误处理。在某些情况下,Axios 的默认行为应该在它应该抛出任何错误的地方保留,我已经通过将

{ throw: true }
传递给
config
参数的重载成功地实现了这一点。我不喜欢的是实施的冗长。有没有办法让下面的重载更干?理想情况下声明泛型
Schema
Parsed
一次而不是重复它们三次?

import type { AxiosRequestConfig } from 'axios';
import * as z from 'zod';
import * as URLS from '~/constants/api-url-constants';
import { coerceError } from '~/utils';

type Result<T> = { ok: true; response: T } | { ok: false; error: Error };
type Url = string | ((urls: typeof URLS) => string);

interface Config<Schema extends z.Schema, Throw extends boolean>
  extends AxiosRequestConfig {
  schema?: Schema | ((zod: typeof z) => Schema);
  throw?: Catch;
}

/**
 * Axios wrapper which accepts Zod-schema to parse
 * response data and return typed response inferred from schema's output type.
 * Schema validations happens in `config.transformResponse`,
 * meaning that failed Zod parsing is able to be intercepted.
 *
 * Returns discriminated union by default for error handling.
 * Use overload `config.catch` to throw unsuccessful api-call like native axios.
 */
async function axiosWrapper<
  Schema extends z.Schema = z.ZodUnknown,
  Parsed = z.output<Schema>,
>(url: Url, config: Config<Schema, false>): Promise<Result<Parsed>>;

async function axiosWrapper<
  Schema extends z.Schema = z.ZodUnknown,
  Parsed = z.output<Schema>,
>(url: Url, config: Config<Schema, true>): Promise<Parsed>;

async function axiosWrapper<
  Schema extends z.Schema = z.ZodUnknown,
  Parsed = z.output<Schema>,
>(url: Url, config: Config<Schema, boolean>): Promise<Result<Parsed> | Parsed> {
  // …implmentation
}
typescript generics overloading
1个回答
0
投票

可以减少您必须编写的泛型数量,并且通常可以在此处删除重复代码。但是,它也会改变您使用该功能的方式。

例如,以下将起作用:

type AxiosWrapperFunction<
  Schema extends z.Schema = z.ZodUnknown,
  Parsed = z.output<Schema>
> = {
  (url: Url, config: Config<Schema, false>): Promise<Result<Parsed>>;
  (url: Url, config: Config<Schema, true>): Promise<Parsed>;
};

export const createAxiosWrapper = <
  Schema extends z.Schema = z.ZodUnknown,
  Parsed = z.output<Schema>
>(): AxiosWrapperFunction<Schema, Parsed> => {
  return (url: Url, config: Config<Schema, boolean>) => {
    /** implementation */
  };
}

在这种情况下,我们必须创建一个包装函数,因为它也必须能够将泛型传递给实现函数。

缺点是,我们现在必须按如下方式使用函数:

const axiosWrapper = createAxiosWrapper</** your generics */>();

axiosWrapper(/** your arguments */)

而不是能够做到:

axiosWrapper</** your generics */>(/** your arguments */)

我的建议是继续重写泛型并坚持实现函数重载

© www.soinside.com 2019 - 2024. All rights reserved.