TypeScript:如何创建一个类型或接口(interface),它是一个具有 n 个键之一或者是字符串的对象?

标签 typescript types typescript-typings

我需要创建一个接口(interface),该接口(interface)可以是字符串,也可以是具有三个键之一的对象。

基本上我有一个函数,它根据错误返回一些东西:

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 并且如果它有它的键之一,它只有一个.

您将如何设计这样的类型或接口(interface)?

编辑:我尝试通过给键一个问号来使键可选,但随后我的 linter 在 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)

Playground example

这表明您可以在参数签名中使用 object。如果你想要求三个字段之一(我相信这会取消 UNKNOWN_ERROR 分支),你将定义三个接口(interface)并制作 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)

Playground Example

关于TypeScript:如何创建一个类型或接口(interface),它是一个具有 n 个键之一或者是字符串的对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52681528/

相关文章:

typescript - 如果参数是数组返回值数组否则返回值

javascript - Angular AOT : ERROR in ng component html file : Expected 0 arguments, 但得到 1

javascript - expressJS : No overload matches this call 的 TypeScript 错误

reactjs - React Redux 调度函数 : Expected 0 arguments, 但得到 1 TS2554

java - 动态查找表示原始 Java 类型的类

typescript - 在 typescript 更新 2.3.4 => 2.4.2 之后,我得到编译错误 "Cannot find type definition file for ' 反射元数据'。”

reactjs - 找不到名称React $ Node React Native

typescript :可变函数参数取决于前面的参数

java - 类型信息如何存储在内存中(如果有的话)

c++ - 使用数字标识符注册类类型