关于rxjs:Typescript用Observable.of区分联合类型

Typescript discriminated union types with Observable.of

我正在尝试将Typescript 2.0的已区分联合类型与RxJS一起使用,但是我收到一个错误,即我返回的对象不是联合类型的类型之一。

这是我的类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
interface Square {
  kind:"square";
  width: number;
}

interface Circle {
  kind:"circle";
  radius: number;
}

interface Center {
  kind:"center";
}

type Shape = Square | Circle | Center;

我只返回不使用ObservableShape的此函数完全可以编译:

1
2
3
4
5
6
7
8
9
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"};
}

当我尝试像这样返回Observable时:

1
2
3
4
5
6
7
function shapeFactoryAsync(width: number): Observable<Shape> {
  if (width > 5) {
    return Observable.of({kind:"circle", radius: width});
  } else {
    return Observable.of({kind:"center"});
  }
}

我遇到编译错误:

1
2
3
4
5
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"'.

我希望我的第一个返回将是Observable<{ kind:"circle"; radius: number; }>类型的,因为kind是所有Shape类型的区别。奇怪的是,Observable.of({kind:"center"})可以,可能是因为没有其他数据与之相关?

如果我明确分配了对象并为该分配指定了类似的类型,则可以修复该问题:

1
2
let circle: Circle = {kind:"circle", radius: width};
return Observable.of(circle);

虽然这似乎应该是不必要的强制转换。

我只是在做这件事完全错误,还是为了确定kind应该是值"circle"而不是类型string而必须进行强制转换?


使用Observable.of({ kind:"center" })之类的调用,TypeScript无法从匿名参数推断类型。

您可以通过在调用泛型of方法时将类型变量指定为Shape来解决您的问题:

1
2
3
4
5
6
7
function shapeFactoryAsync(width: number): Observable<Shape> {
  if (width > 5) {
    return Observable.of<Shape>({ kind:"circle", radius: width });
  } else {
    return Observable.of<Shape>({ kind:"center" });
  }
}

使用指定的类型变量,TypeScript不再需要推断类型。