typescript - 如何修复 "Argument of type ... is not assignable to parameter of type ..."错误?

标签 typescript

给定

abstract class A {
  constructor() {
    this.initialize()
  }

  initialize<T extends {
    [t in keyof this]?: boolean
  }>(todos?: T) {
    // Do something
  }
}

class B extends A {
  initialize() {
    super.initialize({ // <-- it will throw error starting on this open bracket
        test: false
    })
  }

  test() {
    return 'test'
  }
}

为什么上面的代码抛出错误说明 { test: false } 不能分配给 {[t in keyof this]?: boolean}?虽然很明显。

'test' 是 B 的键之一,对吗? keyof this 将引用 B 的 key ,对吗?

最佳答案

正确的抽象类定义

首先,你在“作弊”。

abstract class A {
  constructor() {
    this.initialize()
    //   ~~~~~~~~~~ this `initialize` is from subclass
  }

  // different from this one here
  initialize<T extends {
    [t in keyof this]?: boolean
  }>(todos?: T) {
    // Do something
  }
}

你只是通过给它们相同的名称和兼容的函数签名(可选的 todos 参数)来欺骗 TS 认为你正在调用相同的 initialize 方法。

你想做的应该写成:

abstract class A {
  constructor() {
    this.initialize()
  }

  // fix 1: delcare abstract method
  abstract initialize(): void

  // fix 2: rename, mark as protected
  protected _initialize<T extends {
    [t in keyof this]?: boolean
  // fix 3: todos probably isn't optional
  }>(todos: T) {
    // Do something
  }
}

class B extends A {
  initialize() {
    super._initialize({
        test: false
    })
  }

  test() {
    return 'test'
  }
}

子类与基类的联系

这是一种方式。子类知道基类,但基类没有义务知道扩展自身的所有子类。因为每个子类可以实现不同的东西,基类应该如何知道所有这些信息?

这就是抽象类的全部意义所在。您在基类上声明抽象方法或属性,这实际上是基类建立的契约。哪个子类想要扩展我?先签契约(Contract)吧!遵守我的条款!

回到你的例子,为什么 A 中的 _initialize 应该知道关于 B 的任何事情? CD 也可以扩展 A。仅仅从 this推断 keyof 子类是不可能的。

所以调用时需要告诉super._initializethis是什么子类。这是一个要求,而不是 TS 的限制。

abstract class A {
  constructor() {
    this.initialize()
  }

  abstract initialize(): void

  // pass subclass type as generic param B
  protected _initialize<B>(todos: {
    [t in keyof B]: boolean
  }) {
    // Do something
  }
}

class B extends A {
  initialize() {
    super._initialize<B>({
      test: true,  // <-- this is correct now
      foobar: true // <-- this triggers error report
    })
  }

  test() {
    return 'test'
  }
}

您可以在 JS 中做很多 hacky 的事情,但不要将 JS 与 TS 混淆。 TS 主要是关于最佳实践,当你打破它们时,你会遇到各种怪癖和错误。你的情况不是TS的限制,那是TS试图说服你回到正轨。

关于typescript - 如何修复 "Argument of type ... is not assignable to parameter of type ..."错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55883031/

相关文章:

typescript - Jest模拟类的类实例和类中的函数

javascript - 用于 React createContext 和 useContext 的 typescript

javascript - 如何从 observable 返回值并将其分配给变量

javascript - 在 Angular2/Typescript 中访问没有 ngModel 的输入字段值

javascript - 在 JavaScript/Node.js 中运行 .map 时如何跳过回调?

typescript 类型任意数量的通用字段

javascript - Angular 2路由解析不同的组件

javascript - 如何通过 Angular2 使用 REST API?

javascript - Angular 异步返回一个由 Promise 给出的值

asynchronous - 在具有异步数据调用的小部件内绑定(bind) "foreach"