【问题标题】:What is the correct way to define a subtype in Flow?在 Flow 中定义子类型的正确方法是什么?
【发布时间】:2017-09-23 15:20:08
【问题描述】:

在下面的代码示例中,意图是scrapeMovies 函数只接受可序列化的对象。

/* @flow */

type SerializableObjectType = {
  [key: string]: string | number | boolean | $ReadOnlyArray<SerializableObjectType> | SerializableObjectType
};

type GuideType = {|
  rid: string
|};

const guide: GuideType = {
  rid: 'foo'
};

const scrapeMovies = async (guide: SerializableObjectType) => {};

scrapeMovies(guide);

https://flow.org/try/#0PQKgBAAgZgNg9gdzCYAoVAXAngBwKZgDKeATgJYCGMZAXhQEYx4Dy9AVngMYYAquBAXjABvVGDABtANZ4sALjABnDOQB2AcwC6C5WvVgAPmFUBXALb1ShsPThwmFVdYAkAJTwUAJs1UwsAQRISCiwAHmJyKloGJlYObj58AD5rCMpqOkYWdi5eflQAXwBudGx8MABxEzJPPETBEQMxMHJPHRUyDVQDYvROOFVlMHVq2oUqmrr+MCFRcVaFAHIoO0XCktR+wYwlTmD8AFk4ADcyPEUZsApFLFVOMAAKEcmFNKjM2JyE-gBKGZThL1UIo9hRDiczoonqM8D8ikA

我不明白 抱怨scrapeMovies 被喂给guide 对象的原因是什么,这是SerializableObjectType 的不太严格的定义。

在这里定义子类型的正确方法是什么?

【问题讨论】:

  • 你的类型看起来很矛盾。 ScrapeMoviesGuideType 仅具有一个属性,而 SerializableObjectType 是通用字典。如果您为scrapeMovies 声明guide: SerializableObjectType,这意味着您可能会传递错误的类型,因为它只接受ScrapeMoviesGuideType
  • 目的是为所有刮板方法定义一种通用类型。特定的刮板方法应该能够将类型限制在通用类型的范围内。正如您所说,SerializableObjectType 是通用字典,但 ScrapeMoviesGuideType 是该字典的子类型。
  • const scrapeMovies: ScrapeMoviesType 告诉 Flow 该函数接受 SerializableObjectType 作为参数。所有其他类型信息已被删除。这意味着您可以将任何可序列化的对象传递给函数,这与实际的函数定义直接矛盾。 “特定的刮板方法应该能够将类型限制在通用类型的范围内。”但如何?如果它只知道它是可序列化的,那就是它所知道的一切。您实际上是在告诉它从超类型 转换为 子类型,这是不允许的。
  • 这是设计上不允许的,还是可能需要的功能?
  • 你会做和this simple double-declaration一样的事情。你有一个接受通用类型的函数,另一个接受特定类型的函数。传递给 scrapeMoviesInnerarg 不匹配。

标签: flowtype javascript flowtype


【解决方案1】:

传递GuideType 代替SerializableObjectType 是传递更具体类型的一个实例。 Flow 默认只允许在函数中输入less specific(逆变/只写)。

要使其工作,您需要将guide 参数标记为covariant。通过将对象标记为$ReadOnly&lt;T&gt;,您将有效地将其标记为协变:

(Try)

type SerializableObjectType = {
  [key: string]: string | number | boolean | $ReadOnlyArray<SerializableObjectType> | SerializableObjectType
};

type GuideType = {|
  rid: string
|};

const guide: GuideType = {
  rid: 'foo'
};

const scrapeMovies = async (guide: $ReadOnly<SerializableObjectType>) => {};

scrapeMovies(guide);

或者,您可以在对象类型声明中使用+ 符号标记specific properties as covariant/read-only

(Try)

type SerializableObjectType = {
  +[key: string]: string | number | boolean | $ReadOnlyArray<SerializableObjectType> | SerializableObjectType
};

type GuideType = {|
  rid: string
|};

const guide: GuideType = {
  rid: 'foo'
};

const scrapeMovies = async (guide: SerializableObjectType) => {};

scrapeMovies(guide);

你为什么要跳这个舞?为什么输入是协变/逆变/whateverariant 很重要?好吧,如果您尝试将guide 参数视为SerializeableObjectType(通用对象映射),并且您将number 写入rid 键,则该guide 对象的其他消费者将无法获得他们期待什么。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-21
    • 2020-01-04
    • 1970-01-01
    • 2015-12-06
    相关资源
    最近更新 更多