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
Shapewhen calling the genericofmethod:With the type variable specified, TypeScript no longer has to infer the type.