为什么我的 TypeScript 报告联合类型错误?
Why does my TypeScript report an error for a union type?
我有:
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
会起作用,但它不起作用。
我假设你有类似的东西:
interface MyData {
type: 'WEBSOCKET' | 'HTTP_STREAM';
connection: WebSocketType | HTTPStreamType;
}
根据此接口,您可以拥有 WEBSOCKET
的 type
和 HTTPStreamType
的 connection
。你没有任何地方保证每个工会成员之间的任何联系。 type
和 connection
都可以是联盟的任何一个成员。
这就是为什么打字稿认为你的守卫没有帮助。
相反,您想要一种不同类型的联合:
type MyData = {
type: 'WEBSOCKET';
connection: WebSocketType;
} | {
type: 'HTTP_STREAM';
connection: HTTPStreamType;
}
此类型表示 MyData
可能是 WEBSOCKET
与 WebSocketType
连接的类型, 或 它可能是 HTTP_STREAM
与 HTTPStreamType
连接。但它永远无法混合第一个 属性 和第二个
现在打字稿可以推断出对其中一个属性的检查允许知道另一个 属性 类型。
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
联合类型必须有一些公共字段,在您的情况下,这样的事情就可以了
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
}
}
我有:
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
会起作用,但它不起作用。
我假设你有类似的东西:
interface MyData {
type: 'WEBSOCKET' | 'HTTP_STREAM';
connection: WebSocketType | HTTPStreamType;
}
根据此接口,您可以拥有 WEBSOCKET
的 type
和 HTTPStreamType
的 connection
。你没有任何地方保证每个工会成员之间的任何联系。 type
和 connection
都可以是联盟的任何一个成员。
这就是为什么打字稿认为你的守卫没有帮助。
相反,您想要一种不同类型的联合:
type MyData = {
type: 'WEBSOCKET';
connection: WebSocketType;
} | {
type: 'HTTP_STREAM';
connection: HTTPStreamType;
}
此类型表示 MyData
可能是 WEBSOCKET
与 WebSocketType
连接的类型, 或 它可能是 HTTP_STREAM
与 HTTPStreamType
连接。但它永远无法混合第一个 属性 和第二个
现在打字稿可以推断出对其中一个属性的检查允许知道另一个 属性 类型。
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
联合类型必须有一些公共字段,在您的情况下,这样的事情就可以了
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
}
}