【问题标题】:Typescript union type is raising an error打字稿联合类型引发错误
【发布时间】:2020-02-04 17:10:21
【问题描述】:

我定义的对象:

export const exceptionMsg: ErrorMessages = {
    badRequest: 'bla bla bla',
    user: {
       notFound: 'The user bla bla bla',
    },
};

我为它定义的接口ErrorMessages

interface ErrorMessages {
    [x: string]: string | { [x: string]: string };
}

基本上,我的对象的属性可以是字符串,也可以是其值也是字符串的对象。这就是我要定义的。但是,在另一个文件中使用此对象时,会引发此错误:

“字符串 | 类型”上不存在属性“未找到” { [x:字符串]:字符串; }'。 类型“字符串”上不存在属性“notFound”。

我使用它的代码是这样的:

throw new BadRequestException(exceptionMsg.pipeline.notFound);

我对 Typescript 比较陌生,但在阅读文档后,我似乎找不到我缺少的东西。

【问题讨论】:

  • 您的意思是当您使用exceptionMsg.notFound 时会引发错误?
  • @TitianCernicova-Dragomir 是的,让我编辑一下

标签: typescript typescript-typings


【解决方案1】:

问题在于,当您将 exceptionMsg 声明为 ErrorMessages 时,来自初始化程序的任何信息(例如属性 userbadRequest)都会丢失,只有声明的类型 ErrorMessages 才知道 exceptionMsg

所以当你访问exceptionMsg.user时,ts根据ErrorMessages中的签名只知道exceptionMsg.user的类型是string | { [x: string]: string }。当您拥有联合类型的属性时,由于该属性可以是这两种类型中的任何一种,因此只有访问两种类型共有的属性才是安全的,因此当您再次向下钻取时,您会收到错误,因为 string 没有索引签名或notFound 属性。

您可以使用类型保护来缩小类型:

if (typeof exceptionMsg.user !== "string") {
  exceptionMsg.user.notFound
}

Playground Link

您真正想要的可能是从常量类型中删除ErrorMessages,然后推理就可以了。如果您想将常量限制为扩展 ErrorMessages,您可以使用通用函数:


function createErrorMessages<T extends ErrorMessages>(o: T): T{
  return o;
}
export const exceptionMsg = createErrorMessages({
    badRequest: 'bla bla bla',
    user: {
       notFound: 'The user bla bla bla',
    },
});

exceptionMsg.user.notFound // ok now

Playground Link

【讨论】:

  • 这正是我想要的。非常感谢。但是,我仍在尝试完全理解 createErrorMessages 函数在做什么。它只是将作为参数作为 ErrorMessages 类型的对象返回的任何内容,但我不明白为什么这不会引发错误,但我的解决方案会引发错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-18
  • 2021-08-05
  • 2018-12-06
  • 2020-11-30
  • 1970-01-01
  • 2020-11-04
相关资源
最近更新 更多