I have class with constructor that can accept object of two types, and then based on what type of object it got, perform different actions.
I’ve seen that it’s possible to use as
keyword for that.
But it feels wrong to me.
export type Angle = {
cos: number;
sin: number
}
export type VectorAngleInit = {
angle: Angle,
magnitude: number
}
export type VectorDInit = {
dx: number,
dy: number
}
export class Vector {
#dx: number;
#dy: number;
constructor(init: VectorAngleInit | VectorDInit) {
if ((init as VectorAngleInit)?.angle) {
const angleInit = init as VectorAngleInit
this.#dx = angleInit.magnitude * angleInit.angle.cos;
this.#dy = angleInit.magnitude * angleInit.angle.sin;
} else {
const dInit = init as VectorDInit
this.#dx = dInit.dx
this.#dy = dInit.dy
}
}
}
Should i do that another way? If so, which way is better you think?
2
Answers
You can use
in
operator narrowing to check for the presence of"angle"
ininit
and narrowinit
to the desired union member without a need for type assertions (what you’re calling "casting"):Playground link to code
The thing you need is called Type Predicate
which is an official way to narrow down your union type. It is a function with a special return type
x is SomeType
which is actually a boolean but informstypescript
compiler that what you actually needs to do is to predicate the type rather than just return a boolean.A sample related to your problem could be this:
First define your
type predicate
functionAnd then use it in your constructor: