创建精确类型的类实例的流程方式

huangapple go评论77阅读模式
英文:

Flow Type: How to create an instance of an exact type from a class

问题

我有以下类型和类:

export type ProductType = {
  id: number,
  name: string,
  slug: string,
  tooltip: string,
  properties?: string[]
};

class Product {
  id: number;
  name: string;
  slug: string;
  tooltip: string;
  properties?: string[];

  constructor(props: $Shape<ProductType>) {
    this.id = props.id;
    this.name = props.name || '';
    this.slug = props.slug || '';
    this.tooltip = props.tooltip || '';
    this.properties = props.properties || [];
  }
}

我希望能够像这样做:

const product: ProductType = new Product({ name: 'test' });

但Flow报错如下:

无法将 `new Product()` 赋值给 `product`因为不精确的 `Product` [1] 与精确的 `ProductType` 不兼容

因此,我想知道是否有任何方法可以从类构造函数返回一个精确/冻结/封闭的对象,或者是否可能实现这一点,如果不可能的话,我还有哪些其他选择。

英文:

I have the following type and class:

export type ProductType = {|
  id: number,
  name: string,
  slug: string,
  tooltip: string,
  properties?: string[]
|};

class Product {
  id: number,
  name: string,
  slug: string,
  tooltip: string,
  properties?: string[]

  constructor(props: $Shape&lt;ProductType&gt;) {
    this.id = props.id;
    this.name = props.name || &#39;&#39;;
    this.slug = props.slug || &#39;&#39;;
    this.tooltip = props.tooltip || &#39;&#39;;
    this.properties = props.properties || [];
  }
}

and I'd like to be able to do something like this:

const product: ProductType = new Product({ name: &#39;test&#39; });

but flows complain saying the following:

Cannot assign `new Product()` to `product` because inexact  `Product` [1] is incompatible with exact  `ProductType`

so I'd like to know if there is any way to return an exact/freeze/seal object from the class constructor or if this is even possible and if not what other alternatives I have.

答案1

得分: 3

抱歉,类实例是不精确的。这里有一个示例:

class Foo {
  foo: string;
  constructor() {
    this.foo = 'foo';
  }
}

class Bar extends Foo {
  bar: string;
  constructor() {
    super();
    this.bar = 'bar';
  }
}

type JustFoo = {| foo: string |};

const x: Foo = new Bar();

// 预期的错误 - 如果 Flow 允许这样做,确切的类型将是不准确的!
const y: JustFoo = x;

const z: JustFoo = { foo: "foo" };

(playground)

在这种情况下,Bar 扩展了 Foo 并添加了一个额外的属性。因为类是按名义类型化的,所以 BarFoo 的子类型。因此,Foo 不能成为 {| foo: string |} 的子类型,否则会破坏类型系统。

创建一个精确对象的推荐方式是像我在这个示例中为 z 所做的那样,只需编写一个对象字面量。

英文:

Unfortunately, class instances are inexact. Here's an illustration:

class Foo {
  foo: string;
  constructor() {
    this.foo = &#39;foo&#39;;
  }
}

class Bar extends Foo {
  bar: string;
  constructor() {
    super();
    this.bar = &#39;bar&#39;;
  }
}

type JustFoo = {| foo: string |};

const x: Foo = new Bar();

// Expected error -- if Flow allowed this, the exact type would be a lie!
const y: JustFoo = x;

const z: JustFoo = { foo: &quot;foo&quot; };

(playground)

In this case, Bar extends Foo and adds an additional property. Because classes are nominally typed, Bar is a subtype of Foo. Therefore, Foo cannot be a subtype of {| foo: string |} without breaking the type system.

The recommended way to create an exact object is to just write an object literal, like I did for z in this example.

huangapple
  • 本文由 发表于 2020年1月3日 19:42:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/59578017.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定