首页 > 解决方案 > T 类型的参数不可分配给 T 类型的参数其中 Y 是 X 的子类

问题描述

我的目标是让父类定义事件,并让子类为它们触发事件,但在这些事件中传递的类型将取决于子类,但它将属于某个基类。很难用语言表达,所以这是我的简化 TypeScript 代码,它仍然会产生错误:

// The type 'T' not being passed in a function argument fixes it.
type Listener<T> = (e: T) => any
class EventEmitter<T> {
  private listeners: Listener<T>[] = []
  fire(data: T): void {}
}
class Node {
  constructor(readonly graph: Graph<Node>, readonly data: string) {}
}
// Error: Property 'file' is missing in type 'Node' but required in type 'FileNode'.
class FileNode extends Node {
  // Error: Type 'Graph<FileNode>' is not assignable to type 'Graph<Node>'.
  constructor(readonly graph: Graph<FileNode>, readonly file: string, data: string) {
    // Error: Argument of type 'Graph<FileNode>' is not assignable to
    // parameter of type 'Graph<Node>'.
    super(graph, data)
  }
}
abstract class Provider<T extends Node> {
  _onDidCreate = new EventEmitter<T>()
  abstract setup(graph: Graph<T>): void
}
class Graph<T extends Node> {
  // Replacing 'T' for 'any' here makes it work too,
  // but that is obviously not a proper fix.
  constructor(readonly provider: Provider<T>) {}
}

我计划像这样使用它,例如:

import * as vscode from "vscode"
// Error: Type 'FileNode' does not satisfy the constraint 'Node'.
export class VSCodeProvider extends Provider<FileNode> {
  constructor(readonly root: string) {
    super()
  }
  setup(graph: Graph<FileNode>) {
    const watcher = vscode.workspace.createFileSystemWatcher(this.root)
    watcher.onDidCreate((fileUri: vscode.Uri) => {
      this._onDidCreate.fire(new FileNode(graph, fileUri.fsPath, "...data..."))
    })
  }
}

如何正确修复这些类型错误?我的一部分感觉这些错误通常只是一个糟糕的设计,所以如果有人建议如何通过更好的结构来解决这些错误,那就更好了。

每个节点都包含确定应该如何构建图的数据,例如应该建立哪些链接,但它只能在了解整个图的情况下这样做,因此需要访问图。我可以交换它并将一个节点传递给图表,但是一个节点需要的图表信息较少,然后一个图表需要一个节点来解决问题,所以这似乎是糟糕的设计。代码似乎受到高度耦合的提供者/图和节点/图的影响。

标签: typescripttypeerror

解决方案


您可以创建一个他们都实现的接口。然后你使用接口作为句柄。

export interface INode{}

export class Node implements INode {...}
export class FileNode implements IProvider {...}

export class VSCodeProvider extends Provider<INode> {...}

或者只是检查现有的类,如果它们有一个通用的接口。


推荐阅读