首页 > 解决方案 > 如果存在某个参数,我如何编写一个需要属性的自定义错误类?

问题描述

我正在创建一个这样的自定义错误类:

import { OperationalError } from './baseErrors';

type ErrorProps = {
  message: string;
  paymentProvider: 'stripe' | 'braintree';
  failedChargeData: {
    errorMessage: string;
    stripePaymentIntentId?: string;
    braintreeChargeId?: string;
    eventType: string;
  };
};

export class FailedPaymentError extends OperationalError {
  constructor({ message, paymentProvider, failedChargeData }: ErrorProps) {
    const properties = { failedChargeData, paymentProvider };
    super(message, properties, 400);
  }
}

我想改善这一点。

我想编写某种条件类型,以便 if paymentProvider === 'stripe', thenErrorProps需要一个stripePaymentIntentId. 而如果paymentProvider === 'braintree',那么 abraintreeChargeId是必需的。

我想我需要做这样的事情吗?

import { OperationalError } from './baseErrors';

type PaymentProvider = 'stripe' | 'braintree';
type ErrorProps<T> = {
  message: string;
  paymentProvider: T;
  failedChargeData: T extends 'stripe'
    ? {
        errorMessage: string;
        stripePaymentIntentId: string;
        eventType: string;
      }
    : {
        errorMessage: string;
        braintreeChargeId: string;
        eventType: string;
      };
};

export class FailedPaymentError extends OperationalError {
  constructor({
    message,
    paymentProvider,
    failedChargeData,
  }: ErrorProps<PaymentProvider>) {
    const properties = { failedChargeData, paymentProvider };
    super(message, properties, 400);
  }
}

所以我可以抛出这样的错误:

const failedChargeData = {
  errorMessage: message,
  stripePaymentIntentId: e.type && e.requestId,
  eventType: e.type || 'unexpectedFailedPayment',
};

throw new FailedPaymentError({
  message,
  paymentProvider: 'stripe',
  failedChargeData,
});

但这并不完全奏效。如果我通过错误的支付提供商,TS 不会抱怨。它也不是特别干燥。

这确实有效,但有几行似乎不必要地重复:

type ErrorProps =
  | {
      message: string;
      paymentProvider: 'stripe';
      failedChargeData: {
        errorMessage: string;
        stripePaymentIntentId: string;
        eventType: string;
      };
    }
  | {
      message: string;
      paymentProvider: 'braintree';
      failedChargeData: {
        errorMessage: string;
        braintreeChargeId: string;
        eventType: string;
      };
    };

我怎样才能做到这一点?谢谢

标签: javascriptnode.jstypescripttypestypescript-generics

解决方案


您上一个示例中的有区别的联合是完全正确的。

您可以通过从基本界面中提取可区分的类型来使其干燥。

type MapErrorProps<T, K> = {
  message: string;
  paymentProvider: T;
  failedChargeData: {
    errorMessage: string;
    eventType: string;
  } & K;
};

// Map each type to a required data interface
type ErrorProps = MapErrorProps<"stripe", { stripePaymentIntentId: string }>
  | MapErrorProps<"braintree", { braintreeChargeId: string }>;
  | MapErrorProps<"iceCream", { flavor: string }>;

推荐阅读