为什么我的TypeScript报告联合类型的错误?

为什么我的TypeScript报告联合类型的错误?,typescript,typeguards,Typescript,Typeguards,我有: 其中: type: 'WEBSOCKET' | 'HTTP_STREAM'; connection: WebSocketType | HTTPStreamType; 我正在努力: interface Header { key: string; val: string; } export interface WebSocketType { websocketUrl: string; } export interface HTTPStreamType { streamU

我有:

其中:

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'.
根据此界面,您可以拥有
WEBSOCKET
type
HTTPStreamType
connection
。你没有任何地方保证每个工会成员之间有任何联系<代码>类型
和连接都可以是联合体的任一成员

这就是为什么typescript认为你的守卫帮不上忙的原因

相反,你想要一种不同的联盟:

interface MyData {
    type: 'WEBSOCKET' | 'HTTP_STREAM';
    connection: WebSocketType | HTTPStreamType;
}
此类型表示
MyData
可以是具有
WebSocketType
连接的类型
WEBSOCKET
,也可以是具有
HTTPStreamType
连接的类型
HTTP\u-STREAM
。但它永远不能将第一种财产和第二种财产混合在一起

现在,typescript可以推断,对其中一个属性的检查允许知道另一个属性类型

使用通过类型检查的代码


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


联合类型必须有一些公共字段,在您的情况下,类似这样的东西可以工作

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
更复杂,并且每个其他属性的类型都相同,该怎么办?我真的要定义它两次吗?一点也不!请参见“我的编辑”,末尾有一个游乐场链接。
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
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
  }
}