如何在打字稿中使用联合类型

时间:2021-06-09 18:10:58

标签: javascript node.js typescript

我在一个项目中使用 typescript,在其中的某些部分我必须使用联合类型。但是我收到了一些我不知道如何处理的奇怪错误消息。 考虑以下类型:

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

我使用 [_: string]: 是因为我应该可以使用任意键。该值可以是指示类型的字符串,也可以是提供更多详细信息的对象。 现在考虑以下函数:

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

当我用下面的对象调用上面的函数时:

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

打字稿给出以下错误:

<块引用>

'{ username: { type: string; } 类型的参数可选:布尔值; };地址:{ 类型:字符串; };城市:字符串; }' 不能分配给 'body' 类型的参数。

<块引用>

属性“用户名”与索引签名不兼容。

<块引用>

输入'{类型:字符串;可选:布尔值; }' 不能分配给类型 '"string" | "数" | "布尔值" | { 类型:“字符串” | "数" | "布尔值";可选?:布尔值 |不明确的; } | { [_: 字符串]: 任何;类型:“数组”;项目:“字符串” | "数" | "布尔值";可选?:布尔值 |不明确的; }'。

<块引用>

类型“{ type: string;”中缺少属性“items”可选:布尔值; }' 但需要在类型 '{ [_: string]: any;类型:“数组”;项目:“字符串” | "数" | "布尔值";可选?:布尔值 |不明确的; }'。

我该如何解决这个问题? 谢谢

2 个答案:

答案 0 :(得分:3)

您可以明确声明您的属性 data 是什么类型

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

或投射它

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

答案 1 :(得分:3)

这里的问题是对 data 变量类型的推断过于宽泛。看看reproduction here

如果将鼠标悬停在 data 变量上,您会注意到它被赋予了推断类型:

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

分解您的错误消息,我们看到第一行:

<块引用>

属性“用户名”与索引签名不兼容。

表示 username 是这里的问题。从推断类型中可以看出,该属性的类型为 {type: string, optional: boolean}

您可能认为这与

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

联合的一部分,但是关键区别在于联合的这一部分要求 type 属性具有文字字符串类型之一,并且 < em>不允许任何字符串(由类型 'boolean' | 'number' | 'string' 表示(不带引号))。

这就是为什么它然后尝试匹配您联合的最后一部分,由于索引签名,这将允许 string 键/值对。但是联合的最后一部分还需要一个 type: string 属性,这就是导致您看到的特定错误的原因。


那你是怎么解决的?那么你需要给打字稿一个提示,你的 Items 对象的 username.type 属性不仅仅是任何字符串。以下是一些不同的方法:

  • 使用显式声明或强制转换,使用 data 类型,如 Andreas 的出色回答。
  • 仅投射该属性的值:body。您必须对所有三个属性执行此操作,因此在这种特殊情况下这不是很理想。
  • 将整个对象声明为常量:type: 'string' as 'string'
  • 或者只是使用内联对象而不是先声明它:
const data = { ... } as const