【问题标题】:Typescript class extends from other class cannot be used as interface attributesTypescript 类扩展自其他类不能用作接口属性
【发布时间】:2021-09-04 05:04:02
【问题描述】:

我正在写一个对象接口,其中一个是一个属性值是一个类。但是 ts 编译器会当这个类扩展其他类时抛出异常

这是一个简单的例子:

class Base {
    key: string
}

class Foo extends Base { }

interface Obj {
    list: Foo[]
    value: Foo
}

const obj: Obj = {
    list: [new Foo()],
    value: Foo // < Throws error here
}

错误内容:

Property 'key' is missing in type 'typeof Foo' but required in type 'Base'.ts(2741)
test.ts(39, 5): 'key' is declared here.
test.ts(51, 12): Did you mean to use 'new' with this expression?

当我删除 Foo 中的扩展时,错误消失了:

class Foo { } // < delete extends here

interface Obj {
    list: Foo[]
    value: Foo
}

const obj: Obj = {
    list: [new Foo()],
    value: Foo // < No error throw
}

据我了解,Foo 是从Base 扩展而来的,因此它应该在Base 中包含相关属性,但编译器告诉我它没有。

那么有什么办法可以解决这个问题吗?

泛型错误

还有一个问题。当我在Obj 上使用泛型时,因为有多种类型扩展Base。像这样:

class Foo extends Base { }

class Bar extends Base { }

interface Obj<T extends Base> {
    list: Foo[]
    value: typeof T // < Throws error here
}

const obj: Obj<Foo> = {
    list: [new Foo()],
    value: Foo 
}

编译器会抛出如下异常:

'T' only refers to a type, but is being used as a value here.

有没有办法让泛型定义更完整一点?

我使用的版本

  • 节点12.16.1
  • 打字稿3.8.34.3.4

【问题讨论】:

    标签: javascript typescript class extends


    【解决方案1】:

    key 是您班级 Base 中的必填字段。这就是为什么那个错误。您可以将属性 key 设为可选或在 BaseFoo 中编写构造函数。

    key 属性设为可选:

    class Base {
        key?: string
    }
    
    class Foo extends Base { }
    
    interface Obj {
        list: Foo[]
        value: Foo
    }
    
    const obj: Obj = {
        list: [new Foo()],
        value: new Foo()
    }
    

    制作key 强制属性:

    class Base {
        key: string
    
        constructor(key: string) {
            this.key = key;
        }
    }
    
    class Foo extends Base {
        constructor(key: string) {
            super(key);
        }
    }
    
    interface Obj {
        list: Foo[]
        value: Foo
    }
    
    const obj: Obj = {
        list: [new Foo()],
        value: new Foo()
    }
    

    另外,obj 初始化应该为属性valuenew Foo()Obj 接口内的value 的类型应该是typeof Foo

    【讨论】:

      【解决方案2】:
      Obj 接口中的

      valueFoo 类的实例,而不是类本身。因此,将value 属性为Foo 类的对象分配给接口类型的变量是错误的。您应该将value 设置为Foo 的一个实例(例如new Foo(),这是编译器错误消息所暗示的),或者如果您真的打算使用Foo,请在Obj 中声明value: typeof Foo

      Foo 不扩展 Base 时这种方法起作用的原因是 TypeScript 的结构类型:Foo 没有任何属性,因此 任何 对象,包括一个类,都可以分配给该类型的变量,即使它在运行时可能不是Foo 的实际实例。

      针对有关泛型的附加问题:

      typeof TT 是类型参数时无效,因为T 不必是类。它可以是在结构上与Base 兼容的接口,并且接口没有可以用typeof 检索其类型的“接口对象”。您可以使用Obj 的这个定义,它有效,但需要在使用站点使用typeof

      interface Obj<T extends new (...args: any[]) => Base> {
          list: Foo[],
          value: T
      }
      
      const obj: Obj<typeof Foo> = {
          list: [new Foo()],
          value: Foo
      }
      

      【讨论】:

      • 谢谢你的回答,这个是正确的,不过我在此基础上发现了一个新问题。上面的问题我加了,你怎么看?
      猜你喜欢
      • 2016-12-18
      • 2018-06-20
      • 1970-01-01
      • 2016-09-17
      • 2019-04-07
      • 1970-01-01
      • 2016-07-29
      • 2021-08-07
      • 2015-04-01
      相关资源
      最近更新 更多