简体   繁体   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?

I need to create an interface that is either a string or an object with one of three keys. 我需要创建一个接口,它是一个字符串或一个具有三个键之一的对象。

Basically I have a function that depending on the error returns something: 基本上我有一个函数,根据错误返回一些东西:

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;
  }
};

Here are the types: 以下是类型:

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];
}

But the way I designed ServerAlerts here does not work for me, since ServerAlerts can also be a string and if it has one of its keys, it only has one. 但是我在这里设计ServerAlerts的方式对我来说不起作用,因为ServerAlerts也可以是一个string ,如果它有一个键,它只有一个。

How would you design such a type or interface? 你会如何设计这样的类型或界面?

EDIT: I tried making the keys optional by giving them a question mark, but then my linter complains in the respective key's error return statement in determineError . 编辑:我试图使通过给他们一个问号可选的钥匙,但后来我的棉短绒在各个键的错误return语句抱怨determineError

If I'm understanding you correctly, just declare the parameter as being either ServerAlerts or string : 如果我正确理解你,只需将参数声明为ServerAlertsstring

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

In a comment you've said that all three of the ServerAlerts properties are optional, so you need to mark them as such with ? 在评论中你已经说过所有三个ServerAlerts属性都是可选的,所以你需要将它们标记为? :

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

However, that means that anything typed object will also work, because all the fields are optional. 但是,这意味着任何类型化object都可以工作,因为所有字段都是可选的。 So if you do both of those things, you get: 所以如果你做这两件事,你会得到:

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 游乐场的例子

Which suggests you might just use object in the parameter signature. 这表明您可能只在参数签名中使用object If you want to require one of the three fields (which I believe would do away with that UNKNOWN_ERROR branch), you'd define three interfaces and make ServerAlerts a union of them: 如果你想要求这三个领域之一(我相信会做掉与UNKNOWN_ERROR分支),您可以定义三种接口,使ServerAlerts他们的工会:

interface ServerAlertsNonFieldErrors {
  non_field_errors: [string];
}

interface ServerAlertsDetail {
  detail: string;
}

interface ServerAlertsEmail {
  email: [string];
}

type ServerAlerts = ServerAlertsNonFieldErrors | ServerAlertsDetail | ServerAlertsEmail;

Then you'd use type assertions when returning the specific field: 然后在返回特定字段时使用类型断言:

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

If you do that, then you get: 如果你这样做,那么你得到:

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 游乐场示例

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 TypeScript:如何为具有许多相同类型的键和相同类型的值的对象创建接口? - TypeScript: How to create an interface for an object with many keys of the same type and values of the same type? 如何仅收集具有 object 类型的键,其中某些特定键作为 Typescript 接口中的值? - How to only collect keys in a type that has an object with some specific key as a value in Typescript interface? 是否可以在 TypeScript 上创建一个 object 接口,允许灵活数量/类型的键? - Is it possible to create an object interface on TypeScript that allows a flexible number/type of keys? 创建仅使用字符串键扩展接口的 TypeScript 泛型类型 - Create TypeScript generic type that extends interface with only string keys 带有由接口定义的字符串键和内容的打字稿类型对象 - typescript type object with string keys and content defined by interface 打字稿:输入对象具有接口键的子集 - Typescript: Input object has subset of keys of an interface 如何基于 TypeScript 中的 const object 的键/值创建 object 类型? - How to create an object type based on keys/values of a const object in TypeScript? 如何在typescript对象接口中键入字符串作为Object属性键? - How to type a string as an Object property-key in a typescript Object interface? 如何创建一个对象类型,它具有动态数量的键,具体取决于同一对象中字符串数组的值? - How to create a type of an object, which has a dynamic number of keys, depending on the values of a string array, which is in the same object? 枚举/类型/字符串作为 object 类型/接口中的键 - Enum/Type/string as keys in object Type/interface
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM