【问题标题】:How to use polymorphism with generics in Typescript?如何在 Typescript 中使用泛型的多态性?
【发布时间】:2021-07-26 17:06:55
【问题描述】:

如果我有一个类型的对象,它采用扩展另一个接口/类型的泛型 T。如何键入对象/方法参数以允许任何子类型泛型。

一个例子会更容易理解:

type Options = {
  id: string;
};

type Task<O extends Options = Options> = {
  start: (options: O) => void;
};

const t1: Task<Options> = {
  start: ({ id }) => {
    console.log(id);
  }
};
const t2: Task<{ id: "static"; foo: true } & Options> = {
  start: ({ id, foo }) => {
    console.log(id, foo);
  }
};

const TaskManager = {
  registerTask: (task: Task) => { // maybe I miss something here, I would like to avoid Task<any>
    // use task
  }
};
TaskManager.registerTask(t1); // Ok
TaskManager.registerTask(t2); // ERROR: Argument of type 'Task<{ id: "static"; foo: true; } & Options>' is not assignable to parameter of type 'Task<Options>'.

如何修改 registerTask 以允许任何接受 Task&lt;T extends Options&gt;Task

有人可以帮我解决这个打字问题吗?

编辑: 另外,如果TaskManager存储了一个Task数组,如何用泛型输入这个数组?

class TaskManager {
  private static tasks: Task[] = [];
  public static registerTask = <O extends Options>(task: Task<O>) => {
    TaskManager.tasks.push(task); // ERROR: Argument of type 'Task<O>' is not assignable to parameter of type 'Task<Options>'
  };
}

我需要在班级级别提供泛型吗?

临时解决办法是声明一个Task&lt;any&gt;的数组:

private static tasks: Task<any>[] = [];

允许任何子类型。

【问题讨论】:

    标签: typescript types


    【解决方案1】:

    您可以像这样将TaskManager.registerTask() 设为generic 方法:

    const TaskManager = {
      registerTask: <O extends Options>(task: Task<O>) => {
    
      }
    };
    

    这将导致编译器在您调用它时推断O

    TaskManager.registerTask(t1); // okay
    // (property) registerTask: <Options>(task: Task<Options>) => void
    
    TaskManager.registerTask(t2); // okay
    // (property) registerTask: <{ id: "static"; foo: true; } & Options>(
    //   task: Task<{ id: "static";  foo: true; } & Options>
    // ) => void
    

    Playground link to code

    【讨论】:

    • 感谢错过!
    • 如果我需要在 TaskManager 中存储一个任务数组,我如何使用 extends Options 键入这个数组(请参阅我在原始帖子中的编辑)。
    • TypeScript 没有存在类型,但通常不需要它们。如果您不知道每个O 有什么,那么您实际上会对Task[] 数组做什么......您不能调用它的start() 方法。所以你不妨只取一个Task&lt;never&gt;[] 的数组,比如this。我需要更多 minimal reproducible example 来了解您将如何使用它。但请注意,此修改是一项重大的范围变更; followup questions should be new questions, not edits to the original.
    • 你说得对。我简化了很多代码,只关注打字问题。
    猜你喜欢
    • 2023-03-29
    • 1970-01-01
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-18
    • 2023-03-05
    相关资源
    最近更新 更多