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

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

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

问题

我有以下类型和类:

  1. export type ProductType = {
  2. id: number,
  3. name: string,
  4. slug: string,
  5. tooltip: string,
  6. properties?: string[]
  7. };
  8. class Product {
  9. id: number;
  10. name: string;
  11. slug: string;
  12. tooltip: string;
  13. properties?: string[];
  14. constructor(props: $Shape<ProductType>) {
  15. this.id = props.id;
  16. this.name = props.name || '';
  17. this.slug = props.slug || '';
  18. this.tooltip = props.tooltip || '';
  19. this.properties = props.properties || [];
  20. }
  21. }

我希望能够像这样做:

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

但Flow报错如下:

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

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

英文:

I have the following type and class:

  1. export type ProductType = {|
  2. id: number,
  3. name: string,
  4. slug: string,
  5. tooltip: string,
  6. properties?: string[]
  7. |};
  8. class Product {
  9. id: number,
  10. name: string,
  11. slug: string,
  12. tooltip: string,
  13. properties?: string[]
  14. constructor(props: $Shape&lt;ProductType&gt;) {
  15. this.id = props.id;
  16. this.name = props.name || &#39;&#39;;
  17. this.slug = props.slug || &#39;&#39;;
  18. this.tooltip = props.tooltip || &#39;&#39;;
  19. this.properties = props.properties || [];
  20. }
  21. }

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

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

but flows complain saying the following:

  1. 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

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

  1. class Foo {
  2. foo: string;
  3. constructor() {
  4. this.foo = 'foo';
  5. }
  6. }
  7. class Bar extends Foo {
  8. bar: string;
  9. constructor() {
  10. super();
  11. this.bar = 'bar';
  12. }
  13. }
  14. type JustFoo = {| foo: string |};
  15. const x: Foo = new Bar();
  16. // 预期的错误 - 如果 Flow 允许这样做,确切的类型将是不准确的!
  17. const y: JustFoo = x;
  18. const z: JustFoo = { foo: "foo" };

(playground)

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

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

英文:

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

  1. class Foo {
  2. foo: string;
  3. constructor() {
  4. this.foo = &#39;foo&#39;;
  5. }
  6. }
  7. class Bar extends Foo {
  8. bar: string;
  9. constructor() {
  10. super();
  11. this.bar = &#39;bar&#39;;
  12. }
  13. }
  14. type JustFoo = {| foo: string |};
  15. const x: Foo = new Bar();
  16. // Expected error -- if Flow allowed this, the exact type would be a lie!
  17. const y: JustFoo = x;
  18. 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:

确定