【问题标题】:Why does my TypeScript report an error for a union type?为什么我的 TypeScript 报告联合类型的错误?
【发布时间】:2020-10-02 17:28:30
【问题描述】:

我有:

type: 'WEBSOCKET' | 'HTTP_STREAM';
connection: WebSocketType | HTTPStreamType;

地点:

interface Header {
  key: string;
  val: string;
}

export interface WebSocketType {
  websocketUrl: string;
}

export interface HTTPStreamType {
  streamUrl: string;
  method: 'get' | 'put';
  headers: Header[];
}

我正在尝试:

        if (newStream.type === 'WEBSOCKET') {
          if (newStream?.connection?.websocketUrl?.length > 0) {
            return setIsNextDisabled(false)
          }
        }

但我得到的错误是:

Property 'websocketUrl' does not exist on type 'WebSocketType | HTTPStreamType'.
  Property 'websocketUrl' does not exist on type 'HTTPStreamType'.

我认为guard 会起作用,但它不起作用。

【问题讨论】:

  • 你应该给出一个完整的(非)工作示例。

标签: typescript typeguards


【解决方案1】:

我假设你有类似的东西:

interface MyData {
    type: 'WEBSOCKET' | 'HTTP_STREAM';
    connection: WebSocketType | HTTPStreamType;
}

根据此界面,您可以拥有WEBSOCKET 的type 和HTTPStreamType 的connection。你在任何地方都没有保证每个工会的成员之间有任何联系。 type 和 connection 都可以是工会的成员。

这就是 typescript 认为你的警卫没有帮助的原因。

相反,您需要一种不同的联合:

type MyData = {
    type: 'WEBSOCKET';
    connection: WebSocketType;
} | {
    type: 'HTTP_STREAM';
    connection: HTTPStreamType;
}

这种类型表示MyData 可以是带有WebSocketType 连接的WEBSOCKET 类型,或它可以是带有HTTPStreamType 连接的HTTP_STREAM 类型。但它永远不能混合第一个属性和第二个属性。

现在打字稿可以推断出对其中一个属性的检查允许知道另一个属性类型。

Playground 带有通过类型检查的代码。


通过一些重构,您可以避免重复公共属性like so。

interface MyCommonData {
    foo: string
    bar: number
}

interface WebSocketData extends MyCommonData {
    type: 'WEBSOCKET'
    connection: WebSocketType
}

interface HttpStreamData extends MyCommonData {
    type: 'HTTP_STREAM';
    connection: HTTPStreamType;
}

type MyData = WebSocketData | HttpStreamData

【讨论】:

  • 那么,如果MyData 更复杂并且所有其他属性的类型都相同怎么办?我真的需要定义两次吗?
  • 一点也不!看到我的编辑,最后有一个游乐场链接。
【解决方案2】:

联合类型必须有一些公共字段,在你的情况下这样的事情会起作用

interface Header {
  key: string;
  val: string;
}

export interface WebSocketType {
  url: string;
}

export interface HTTPStreamType {
  url: string;
  method: 'get' | 'put';
  headers: Header[];
}

export class Stream { 

  constructor(
    public _type: 'WEBSOCKET' | 'HTTP_STREAM',
    public connection: WebSocketType  | HTTPStreamType
  ) { }
}




let newStream = new Stream('WEBSOCKET', { url: 'myurl' })
let newStream2 = new Stream(
  'HTTP_STREAM',
  { url: 'meaw', method: 'get', headers: [
    { key: 'someheader', val: 'somevalue' }
  ]
  })

if (newStream._type === 'WEBSOCKET') {
  if (newStream.connection.url.length > 0) {
    //do stuff
  }
}

if (newStream2._type === 'HTTP_STREAM') {
  if (newStream2.connection.url.length > 0) {
    //do stuff
  }
}

【讨论】:

    猜你喜欢
    • 2019-08-01
    • 1970-01-01
    • 2011-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-09
    • 1970-01-01
    • 2022-06-10
    相关资源
    最近更新 更多