I have:
type: 'WEBSOCKET' | 'HTTP_STREAM';
connection: WebSocketType | HTTPStreamType;
where:
interface Header {
key: string;
val: string;
}
export interface WebSocketType {
websocketUrl: string;
}
export interface HTTPStreamType {
streamUrl: string;
method: 'get' | 'put';
headers: Header[];
}
I'm trying:
if (newStream.type === 'WEBSOCKET') {
if (newStream?.connection?.websocketUrl?.length > 0) {
return setIsNextDisabled(false)
}
}
but the error I get is:
Property 'websocketUrl' does not exist on type 'WebSocketType | HTTPStreamType'.
Property 'websocketUrl' does not exist on type 'HTTPStreamType'.
I thought the guard
would work, but it doesn't.
I assume you have something like:
interface MyData {
type: 'WEBSOCKET' | 'HTTP_STREAM';
connection: WebSocketType | HTTPStreamType;
}
According to this interface, you could have a type
of WEBSOCKET
and a connection
of the HTTPStreamType
. Nowhere have you guaranteed any linkage between members of each union. type
and connection
could both be either member of the union.
That is is why typescript doesn't think your guard has helped.
Instead, you want a different kind of union:
type MyData = {
type: 'WEBSOCKET';
connection: WebSocketType;
} | {
type: 'HTTP_STREAM';
connection: HTTPStreamType;
}
This type says that MyData
could be a type WEBSOCKET
with a WebSocketType
connection, or it could be a type HTTP_STREAM
with a HTTPStreamType
connection. But it could never mix one property from the first, and another from the second.
Now typescript can infer that a a check against one of the properties allows the other property type to be known.
Playground with code that passes type checking.
With some refactoring you can avoid repeating common properties 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
Union types must have some common fields, in your case something like this would work
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
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With