簡體   English   中英

TypeScript:如何創建一個類型或接口,它是一個具有n個鍵之一或是字符串的對象?

[英]TypeScript: How to create a type or interface that is an object that has one of n keys or is a string?

我需要創建一個接口,它是一個字符串或一個具有三個鍵之一的對象。

基本上我有一個函數,根據錯誤返回一些東西:

export const determineError = (error: ServerAlerts): AlertError => {
  if (typeof error !== "string") {
    if (error.hasOwnProperty("non_field_errors")) {
      return error.non_field_errors[0];
    } else if (error.hasOwnProperty("detail")) {
      return error.detail;
    } else if (error.hasOwnProperty("email")) {
      return error.email[0];
    } else {
      return UNKNOWN_ERROR;
    }
  } else {
    return error;
  }
};

以下是類型:

export type AlertError =
  | "Unable to log in with provided credentials."
  | "E-mail is not verified."
  | "Password reset e-mail has been sent."
  | "Verification e-mail sent."
  | "A user is already registered with this e-mail address."
  | "Facebook Log In is cancelled."
  | string;

export interface ServerAlerts {
  non_field_errors: [string];
  detail: string;
  email: [string];
}

但是我在這里設計ServerAlerts的方式對我來說不起作用,因為ServerAlerts也可以是一個string ,如果它有一個鍵,它只有一個。

你會如何設計這樣的類型或界面?

編輯:我試圖使通過給他們一個問號可選的鑰匙,但后來我的棉短絨在各個鍵的錯誤return語句抱怨determineError

如果我正確理解你,只需將參數聲明為ServerAlertsstring

export const determineError = (error: ServerAlerts|string): AlertError => {
// -----------------------------------------------^^^^^^^

在評論中你已經說過所有三個ServerAlerts屬性都是可選的,所以你需要將它們標記為?

interface ServerAlerts {
  non_field_errors?: [string];
  detail?: string;
  email?: [string];
}

但是,這意味着任何類型化object都可以工作,因為所有字段都是可選的。 所以如果你做這兩件事,你會得到:

determineError("foo");                       // Works
determineError({ non_field_errors: ["x"] }); // Works
determineError({ detail: "x" });             // Works
determineError({ email: ["x"] });            // Works
determineError({});                          // Works (because all fields are optional)
let nonLiteralServerAlerts: object;
nonLiteralServerAlerts = { foo: ["x"] };
determineError(nonLiteralServerAlerts);      // Works (because all fields are optional)
determineError({ foo: ["x"] });              // Fails (correctly)

游樂場的例子

這表明您可能只在參數簽名中使用object 如果你想要求這三個領域之一(我相信會做掉與UNKNOWN_ERROR分支),您可以定義三種接口,使ServerAlerts他們的工會:

interface ServerAlertsNonFieldErrors {
  non_field_errors: [string];
}

interface ServerAlertsDetail {
  detail: string;
}

interface ServerAlertsEmail {
  email: [string];
}

type ServerAlerts = ServerAlertsNonFieldErrors | ServerAlertsDetail | ServerAlertsEmail;

然后在返回特定字段時使用類型斷言:

if (error.hasOwnProperty("non_field_errors")) {
  return (error as ServerAlertsNonFieldErrors).non_field_errors[0];
// ------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

如果你這樣做,那么你得到:

determineError("foo");                       // Works
determineError({ non_field_errors: ["x"] }); // Works
determineError({ detail: "x" });             // Works
determineError({ email: ["x"] });            // Works
determineError({});                          // Fails (correctly)
let nonLiteralServerAlerts: object;
nonLiteralServerAlerts = { foo: ["x"] };
determineError(nonLiteralServerAlerts);      // Fails (correctly)
determineError({ foo: ["x"] });              // Fails (correctly)

游樂場示例

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM