If I have a base class and multiple sub classes that inherit from this base, e.g:
class Message {
constructor(public text: string) {}
}
class MessageA extends Message {
msgType: string = 'A';
constructor(
public text: string,
public aData: string
) {
super(text);
}
}
class MessageB extends Message {
msgType: string = 'B';
constructor(
public text: string,
public bData: number
) {
super(text);
}
}
… is it possible to create a type that only admits the sub classes?
I want something like
type Msg = MessageA | MessageB;
… that would allow me to write
const show = (msg: Msg): void => {
switch (msg.msgType) {
case 'A':
return console.log(`${msg.text}: ${msg.aData}`);
case 'B':
return console.log(`${msg.text}: ${msg.bData}`);
}
}
However, the code above gives me this error:
Property 'aData' does not exist on type 'Msg'.
Property 'aData' does not exist on type 'MessageB'.
If I change the type to be the following, show works again:
type Msg = ({msgType: 'A'} & MessageA)
| ({msgType: 'B'} & MessageB);
But if I then call show with a new MessageB…
show(new MessageB('hello', 300));
… I get this error:
Argument of type 'MessageB' is not assignable to parameter of type 'Msg'.
Type 'MessageB' is not assignable to type '{ msgType: "B"; } & MessageB'.
Type 'MessageB' is not assignable to type '{ msgType: "B"; }'.
Types of property 'msgType' are incompatible.
Type 'string' is not assignable to type '"B"'.(2345)
What is a good way to create a type for the subclasses of a base class?
The goal here is to ensure that a handler will inspect the type of the object it was passed before it can access any fields (that aren't in the base class) and also ensure that the switch is exhaustive for when future sub classes are added.