简体   繁体   English

如何在 typescript 中使用联合类型

[英]how to use union types in typescript

I'm using typescript on a project and in some parts of it I have to use union types.我在一个项目中使用 typescript 并且在其中的某些部分我必须使用联合类型。 But I'm getting some weird error messages that I don't know how to deal with.但是我收到了一些奇怪的错误消息,我不知道如何处理。 Consider the type below:考虑以下类型:

type body = {
  [_: string]:
    | 'boolean'
    | 'number'
    | 'string'
    | {
        type: 'boolean' | 'number' | 'string'
        optional?: boolean
      }
    | {
        type: 'array'
        items: 'boolean' | 'string' | 'number'
        optional?: boolean
        [_: string]: any
      }
}

I'm using [_: string]: because I should be able to use any arbitrary key.我正在使用[_: string]:因为我应该能够使用任意键。 The value can either be a string indicating a type or can be a object that provides more details.该值可以是指示类型的字符串,也可以是提供更多详细信息的 object。 Now consider the following function:现在考虑以下 function:

function show(data: body) {
  console.log(data)
}

When I call the above function with the object below:当我用下面的 object 调用上面的 function 时:

const data = {
  username: { type: 'string', optional: false },
  address: { type: 'string' },
  city: 'string'
}

Typescript gives the error below: Typescript 给出以下错误:

Argument of type '{ username: { type: string;类型参数 '{ username: { type: string; optional: boolean;可选:boolean; }; }; address: { type: string;地址:{类型:字符串; }; }; city: string;城市:字符串; }' is not assignable to parameter of type 'body'. }' 不可分配给“body”类型的参数。

Property 'username' is incompatible with index signature.属性“用户名”与索引签名不兼容。

Type '{ type: string;类型'{类型:字符串; optional: boolean;可选:boolean; }' is not assignable to type '"string" | }' 不可分配给类型 '"string" | "number" | "数字" | "boolean" | “布尔” | { type: "string" | {类型:“字符串”| "number" | "数字" | "boolean"; “布尔”; optional?: boolean |可选?:boolean | undefined;不明确的; } | } | { [_: string]: any; { [_:字符串]:任何; type: "array";类型:“数组”; items: "string" |项目:“字符串”| "number" | "数字" | "boolean"; “布尔”; optional?: boolean |可选?:boolean | undefined;不明确的; }'. }'。

Property 'items' is missing in type '{ type: string;类型 '{ type: string; 中缺少属性 'items' optional: boolean;可选:boolean; }' but required in type '{ [_: string]: any; }' 但在类型 '{ [_: string]: any; type: "array";类型:“数组”; items: "string" |项目:“字符串”| "number" | "数字" | "boolean"; “布尔”; optional?: boolean |可选?:boolean | undefined;不明确的; }'. }'。

How can I solve this?我该如何解决这个问题? thanks谢谢

You can explictly declare what type your property data is您可以明确声明您的属性data是什么类型

const data: body = {
  username: { type: 'string', optional: false },
  address: { type: 'string' },
  city: 'string'
}

or cast it或投它

const data = {
  username: { type: 'string', optional: false },
  address: { type: 'string' },
  city: 'string'
} as body;

The issue here is with an overly broad inference on the type of the data variable.这里的问题是对data变量的类型的推断过于广泛。 Take a look at the reproduction here .看看这里的复制品

If you hover your data variable, you'll note that it was given the inferred type:如果你 hover 你的data变量,你会注意到它被赋予了推断的类型:

{
    username: {
        type: string;
        optional: boolean;
    };
    address: {
        type: string;
    };
    city: string;
}

Breaking down your error message, we see the first line:分解您的错误消息,我们看到第一行:

Property 'username' is incompatible with index signature.属性“用户名”与索引签名不兼容。

Indicates that username is the issue here.表示username是这里的问题。 As you can see from the inferred type, that property has the type {type: string, optional: boolean} .从推断的类型中可以看出,该属性的类型为{type: string, optional: boolean}

You might think that this would match to the您可能认为这将与

{ type: 'boolean' | 'number' | 'string', optional?: boolean }

part of your union, however the critical difference is that this part of your union requires the type property to have one of the literal string types 'boolean' | 'number' | 'string'联合的一部分,但关键的区别在于联合的这一部分要求type属性具有文字字符串类型之一'boolean' | 'number' | 'string' 'boolean' | 'number' | 'string' 'boolean' | 'number' | 'string' , and does not permit any string (represented by the type string (without quotes)). 'boolean' | 'number' | 'string' ,并且不允许任何字符串(由类型string表示(不带引号))。

This is why it then tries to match to the final piece of your union, which would allow the type: string key/value pair due to the index signature.这就是为什么它会尝试匹配你的联合的最后一块,这将允许type: string键/值对,因为索引签名。 But this last part of the union also requires an Items property which is what is leading to the specific error you see.但是联合的最后一部分还需要一个Items属性,这会导致您看到的特定错误。


So how do you fix it?那么如何解决呢? Well you need to give typescript a hint that the username.type property of your data object is not just any string.那么你需要给 typescript 一个提示,你的data object 的username.type属性不仅仅是任何字符串。 Here are some various ways:这里有一些不同的方法:

  • Use an explicit declaration or cast, using the body type, as in Andreas' excellent answer.如 Andreas 的出色回答一样,使用body类型使用显式声明或强制转换。
  • Cast just that property's value: type: 'string' as 'string' .只转换该属性的值: type: 'string' as 'string' You'd have to do this for all three properties so this is not very ideal in this particular case.您必须对所有三个属性都执行此操作,因此在这种特殊情况下这不是很理想。
  • Declare the entire object as a const: const data = {... } as const将整个 object 声明为 const: const data = {... } as const
  • Or just use the object inline instead of declaring it first:或者只是使用 object 内联而不是先声明它:
show({
  username: { type: 'string', optional: false },
  address: { type: 'string' },
  city: 'string'
});

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM