2017-09-13 87 views
2

我目前正在学习结构分型。我对这样的想法持怀疑态度,认为两种类型被认为是相同的,只是因为它们碰巧有一部分共同的结构。这感觉很像静态鸭子打字,它完全忽略了类型的语义层次。所以我把在普通对象的流动的结构打字定睛一看,也遇到以下行为:流的结构子类型是否“忘记”特定的子类型属性?

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

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

看起来流程的结构分型算法偶尔会忘记特定于某个子类型的属性。这种行为是有意的还是我只是遇到了边缘案例?

+1

你能澄清你的意思吗?通过声明类型':{}',你已经明确地删除了它的类型信息,就像你做了'Animal foo = new Cat()','foo'不知道它是'Cat',它只知道它是一个'动物'。 – loganfsmyth

+0

@loganfsmyth'{}'只是没有任何结构的最一般的普通对象类型。这当然是无用的。问题是,如果我在这个边缘案例中观察到的行为是更深层次的问题的一部分,这个问题是特定于子类型的。 – ftor

+1

我想澄清的是,如果你认为这是一个边缘案例,那么它会是一个问题呢?在JavaScript作为一种无类型语言的情况下,绝对有些情况下你会拥有一个对象,而对它所拥有的属性一无所知。为了得到'foo',你可以这样做:if(typeof o.foo ===“boolean”){/ *用属性作为布尔值* /}来操作,它会很好用。 – loganfsmyth

回答

3

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

举例来说,即使没有结构性打字,如果你这样做

class Animal {} 

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

const c: Animal = new Cat(); 

console.log(c.foo); 

On flow.org/try

它没有类型检查出于同样的原因。在你的例子中,你明确地告诉编译器“考虑o的类型为{}”,就像我在我的例子中所说的“考虑c的类型为Animal”。因此,编译器明确被告知忘记它正在使用Cat,因此它忘记了该对象具有.foo属性。

看起来流程的结构子类型化算法偶尔会忘记特定于某个子类型的属性。这种行为是有意的还是我只是遇到了边缘案例?

所以要回答这个问题,它不会“偶尔”这样做,它完全是在您告诉它这样做的时候做到的。行为是绝对有意的。

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

对象确实包含了属性,这是100%的罚款,但你已经明确的价值转换为一超擦除的信息。

+0

这确实不是我最好的问题之一。感谢您花时间回答它!所以真正的问题是当没有任何明确的注释时流是如何表现的,但是类型必须被推断出来,因为一个对象是由更复杂的组合中的函数返回的。有没有信息丢失?相关:[包含规则](https://news.ycombinator.com/item?id=13047934) – ftor

+1

我觉得我需要一个明确的例子,但据我所知,不应该有任何信息丢失类型推断。 – loganfsmyth

相关问题