我编写了一个util函数,用于解析API异常并返回建模的TS类型.

interface NotFoundException {
  type: 'notFound'
}

interface PermissionException {
  type: 'permission'
}

interface BadRequestException {
  type: 'badRequest'
}

// Example shape of API Error 
interface APIError {
  statusCode: number;
}

type KnownExceptions = NotFoundException | PermissionException | BadRequestException;

function exceptionHandler(err: unknown): KnownExceptions {
  const statusCode = (err as APIError).statusCode ?? -1;

  if (statusCode === 404) {
    return {
      type: 'notFound'
    }
  }

  if (statusCode === 403) {
    return {
      type: 'permission'
    }
  }

  if (statusCode === 400) {
    return {
      type: 'badRequest'
    }
  }

  throw new Error('Unknown error', { cause: err });
}

有些API不会返回所有类型,因此我需要显式处理其他类型

interface APIInput {
  prop: string;
}

interface APIOutput {
  id: string;
}

function callAPI(input: APIInput): APIOutput | PermissionException | NotFoundException {
  try {
    //Mock API call
    return {
      id: 'id'
    };
  } catch (err: unknown) {
    const e = exceptionHandler(err);

    // Problem: This API (and others) cannot throw this/some exceptions

    // Need a function that will restrict the types returned by exceptionHandler
    // and throw 'Unexpected exception' for impossible cases
    if (e.type === 'badRequest') {
      throw new Error('Unexpected exception', { cause: err });
    }

    return e;
  }
}

Playground Link

有没有一种方法可以让我写一个函数,将异常联合的返回类型限制为我想要的类型,并对所有其他类型抛出Unexpected exception个错误?

由于TS不能将类型作为参数,我发现很难弄清楚这一点.

推荐答案

像这样的吗?

type ApiType = 'foo' | 'bar';

type AllowedExceptionsByApiType = {
    foo: PermissionException | NotFoundException,
    bar: BadRequestException
}

function exceptionHandler<T extends ApiType>(apiType: T, error: unknown): AllowedExceptionsByApiType[T] {
    // impl
}

我们在ApiType中声明可能的API类型,然后在AllowedExceptionsByApiType中按每种API类型声明可能的异常.

然后,使用泛型,返回类型exceptionHandler被约束为API类型允许的那些异常.


Example:

function callApi(input: SomeInput): Output | PermissionException | NotFoundException {
    try {
        //API Call
    } catch (err: unknown) {
        const e = exceptionHandler('foo', err);

        // error
        if (e.type === 'badRequestException') {
            throw new Error('Unexpected exception', err);
        }

        // ok
        if (e.type === 'notFound') {
            // impl
        }
    }
}

Typescript相关问答推荐

如何从TypScript中的接口中正确获取特定键类型的所有属性?

如何防止TypeScript允许重新分配NTFS?

如何推断哪个特定密钥与泛型匹配?

从typescript中的对象数组中获取对象的值作为类型'

PrimeNG日历需要找到覆盖默认Enter键行为的方法

接口中函数的条件参数

通过按键数组拾取对象的关键点

<;T扩展布尔值>;

TypeError:正文不可用-NextJS服务器操作POST

(TypeScript)TypeError:无法读取未定义的属性(正在读取映射)"

无法将从服务器接收的JSON对象转换为所需的类型,因此可以分析数据

如何为特定参数定义子路由?

在Thunk中间件中输入额外参数时Redux工具包的打字脚本错误

在Google授权后由客户端接收令牌

从以下内容之一提取属性类型

为什么受歧视的unions 在一种情况下运作良好,但在另一种非常类似的情况下却不起作用?

T的typeof键的Typescript定义

我可以使用对象属性的名称作为对象中的字符串值吗?

为什么 Typescript 无法正确推断数组元素的类型?

为什么 typescript 在对象合并期间无法判断无效键?