I'm trying to use Typescript 2.0's discriminated union types with RxJS, but I'm getting an error that the object I am returning is not of the one of the types of the union type.
Here are my types:
interface Square {
kind: "square";
width: number;
}
interface Circle {
kind: "circle";
radius: number;
}
interface Center {
kind: "center";
}
type Shape = Square | Circle | Center;
This function where I just return a Shape
not using an Observable
compiles completely fine:
function shapeFactory(width: number): Shape {
if (width > 5) {
return {kind: "circle", radius: width};
} else if (width < 2) {
return {kind: "square", width: 3};
}
return {kind: "center"};
}
When I instead try to return an Observable<Shape>
like so:
function shapeFactoryAsync(width: number): Observable<Shape> {
if (width > 5) {
return Observable.of({kind: "circle", radius: width});
} else {
return Observable.of({kind: "center"});
}
}
I am met with the compilation error:
Type 'Observable<{ kind: string; radius: number; }>' is not assignable to type 'Observable<Shape>'.
Type '{ kind: string; radius: number; }' is not assignable to type 'Shape'.
Type '{ kind: string; radius: number; }' is not assignable to type 'Center'.
Types of property 'kind' are incompatible.
Type 'string' is not assignable to type '"center"'.
I expect that my first return would be of type Observable<{ kind: "circle"; radius: number; }>
, since kind
is the discriminate across all Shape
types. Strangely, it is okay with Observable.of({kind: "center"})
, possibly because there's no other data associated with it?
I am able to fix it if I explicitly assign the object and give the assignment a type like so:
let circle: Circle = {kind: "circle", radius: width};
return Observable.of(circle);
Though this seems like it should be an unnecessary cast.
Am I just doing this completely wrong or is that cast necessary in order to figure out that kind
is supposed to be of value "circle"
instead of type string
?
With a call like
Observable.of({ kind: "center" })
, TypeScript is unable to infer the type from the anonymous argument.You can solve your problem by specifying the type variable as
Shape
when calling the genericof
method:With the type variable specified, TypeScript no longer has to infer the type.