2

我目前正在研究结构类型。我怀疑两种类型被认为是等价的,因为它们碰巧有一部分结构是相同的。这感觉很像静态鸭子类型,它完全忽略了类型的语义级别。于是仔细看了一下flow对普通对象的结构类型化,遇到了如下行为:

const o:{} = {foo: true};
o.foo; // type error

{}是结构类型,是所有普通对象的超类型。o因此,我可以用它进行注释是有道理的,因为它{foo: true}{}. 但是,当我尝试访问现有foo属性时,此操作不会键入检查。这很奇怪,因为 AFAIK 结构子类型通常可以包含特定属性,只要它还包括其超类型的所有必需属性。

似乎流的结构子类型算法偶尔会忘记特定于某个子类型的属性。这种行为是有意的还是我只是遇到了边缘情况?

4

1 回答 1

2

您描述的总体问题是从子类型转换为超类型的事实。通过执行强制转换,您明确告诉编译器丢弃有关给定对象的信息。

例如,即使没有结构类型,如果你这样做

class Animal {}

class Cat extends Animal {
  foo: bool = true;
}

const c: Animal = new Cat();

console.log(c.foo);

在 flow.org/try 上

由于同样的原因,它无法进行类型检查。在您的示例中,您已明确告诉编译器“考虑o拥有类型{}”,就像在我的示例中我说过“考虑c拥有类型Animal”一样。因此,编译器被明确告知忘记它正在使用 a Cat,因此它忘记了对象具有.foo属性。

似乎流的结构子类型算法偶尔会忘记特定于某个子类型的属性。这种行为是有意的还是我只是遇到了边缘情况?

因此,要回答这个问题,它不会“偶尔”这样做,它会在您告诉它这样做时准确地执行。这种行为是绝对有意的。

这很奇怪,因为 AFAIK 结构子类型通常可以包含特定属性,只要它还包括其超类型的所有必需属性。

对象确实包含该属性,这是 100% 好的,但您已通过将值转换为超类型来明确删除该信息。

于 2017-09-14T06:05:32.567 回答