带参数的 Typescript 工厂模式

2024-04-06

我目前在我的项目中使用工厂模式,下面是最小的可重现代码

class A {
    constructor(public name: string) {}
}

class B {
    constructor(public age: number, public address: string) {}
}

type FactoryMap = {
    A: A,
    B: B
}

const map = {
    A,
    B
}

function create<T extends keyof FactoryMap>(name: T, ...params: ConstructorParameters<typeof FactoryMap[T]>): FactoryMap[T] {
    switch (name) {
        case "A":
            return new A(...params);
        case "B":
            return new B(...params);
    }
}

function create2<T extends keyof typeof map>(name: T, ...params: ConstructorParameters<typeof map[T]>): typeof map[T] {
    return new map[name](...params);
}

我尝试了两种不同的功能,但都不起作用。

第一个说的是Type 'A' is not assignable to type 'A & B',但我想知道FactoryMap[T]应该A | B.

第二个错误是Type 'A | B' is not assignable to type '{ A: typeof A; B: typeof B; }[T]',我知道为什么,但我无法推断A | B使用该对象map.

有人有这两个功能的解决方案吗?

操场 https://www.typescriptlang.org/play?#code/MYGwhgzhAECC0G8BQ1XWAewHYQC4CcBXYXDfACgAdCAjEAS2GizAFsBTALmj33qwDmASkQBfJOKShIMAEKIUaTDgLFSFanUbQwArs0Ksa7fABpomhkzAATG-nZRuvfsLESkSXAE9K7aABiYCRk3gCyYJTQALwKaHDcsKaKqLLcsh4AZoRYJPTY6A5guOwAPAAq0OwAHiVYNjAA1uzeGJmBwerhkQB85Cwc3OXmAHRjlGD4bBDcAMLYvGpkAAqTbOwl%20BClPn5tHSH43ZQA2uUAuj1C3EGHx2fncWgQAO70uMAAFtD96yLI8XiwEg-gARLBQZwUoD4g5cIR8FhmOwXnByGMRhMpqwIEIANzQoEg6Cg2SQwkw6BwhFIrAo6CydHjNY4-HQ8SSZR4aCsSIxJ6oJLQjLibK5XD5JHAIolABMFSqtXY9SaLX2u3Y%2015lD6A30w2gGKx0zmC1Uh1W2I2Jm2Gq1kQeV24dva2oeAqpGxpyNRbr15yZmJZuIJoiAA


Typescript 将无法评估包含未解析类型参数的条件类型。你可以通过重载来解决这个问题:

class A {
    private name!: string
    constructor() {}
}

class B {
    private age!: number
    constructor() {}
}

const map = { A, B }

function create2<T extends keyof typeof map>(name: T, ...params: ConstructorParameters<typeof map[T]>): InstanceType<typeof map[T]>
function create2(name: keyof typeof map, ...params: ConstructorParameters<typeof map[keyof typeof map]>): InstanceType<typeof map[keyof typeof map]> {
    return new map[name](...params);
}

I added InstanceType关于返回类型。typeof map[keyof typeof map]将成为联盟typeof A | typeof B(即任一类)。由于我们返回一个实例,因此我们需要使用InstanceType得到那个。

如果构造函数有参数,上面的版本实际上将不起作用。这是因为 Typescript 无法遵循这一点params and map[name]以任何方式相关。所以TS看到new (A | B)(...(parmsForA | paramsForB)这只是有时安全(如果AparamsForB这将是一个错误)

现在,既然我们知道两者实际上是相关的,那么这是类型断言的一个很好的用途:

class A {
    constructor(public name: string) {}
}

class B {
    constructor(public age: number, public address: string) {}
}

const map = { A, B }

function create2<T extends keyof typeof map>(name: T, ...params: ConstructorParameters<typeof map[T]>): InstanceType<typeof map[T]>
function create2(name: keyof typeof map, ...params: any[]): InstanceType<typeof map[keyof typeof map]> {
    return new (map[name] as any)(...params)
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

带参数的 Typescript 工厂模式 的相关文章

随机推荐

  • 扩展 Autodesk Forge:将我自己的扩展添加到包后,我的控制面板无法连接到 Revit 模型

    我用过这个包 https github com petrbroz forge iot extensions demo https github com petrbroz forge iot extensions demo 之后 我添加了自己
  • 查找数组长度的时间复杂度

    我对时间复杂度有点困惑len 函数将是 我读过很多不同的文章 在 python 中查找数组的长度是O 1 与len 函数和其他语言类似 这怎么可能 您是否不必遍历整个数组来计算它占用了多少个索引 您是否不必遍历整个数组来计算它占用了多少个索
  • 当第一个查询使用只读数据库时,Android 无法升级我的数据库

    所以到目前为止我一直严重依赖自动化 几乎 onCreate onUpgrade我的方法SQLite数据库 一切都工作正常 我只需更改数据库的版本号即可运行onUpgrade自动地 但现在 当我尝试向数据库添加列并更改版本号时 我遇到了该异常
  • 适用于 Raspberry Pi 的触摸屏 Kivy 应用

    场景如下 我使用 python 框架编写了一个 guiKivy http kivy org 我想在树莓派上运行它这个触摸屏 https learn adafruit com adafruit pitft 28 inch resistive
  • 获取默认远程推送和默认远程分支

    我想从脚本中获取默认的推送远程和默认的推送分支 对于召回 git 将按以下顺序在这些设置之间选择远程 branch
  • Ruby - Proc.call - 捕获异常

    我在捕获调用中的异常和错误时遇到问题Proc object 看我的代码 def method1 do something end def method2 do something end def run method safely proc
  • Ember:在 Mixin 中以编程方式设置 queryParams

    我正在尝试以编程方式在 Ember Mixin 中定义 queryParams mixin 有一个方法 当持有 mixin 的控制器初始化时会调用该方法 setupQueryParams params gt params forEach p
  • 运行JDK代码时Java JIT会作弊吗?

    我正在对一些代码进行基准测试 但我无法让它运行得像java math BigInteger https docs oracle com javase 7 docs api java math BigInteger html 即使使用完全相同
  • MySQL,我应该保持连接还是在需要时连接?

    我一直在将家里的温度记录到 MySQL 数据库 每 5 分钟总共读取 10 个传感器 并且一直在使用 Python 但我想知道一些事情 目前 当我第一次运行程序时 我运行到 MySQL 的正常连接 该连接仅运行一次 db MySQLdb c
  • 如何通过按住Java中的JPanel来移动未修饰的JFrame? [复制]

    这个问题在这里已经有答案了 到目前为止 我一直在制作一个未装饰的 JFrame 我想知道是否可以通过按住 JPanel 上的单击来移动未装饰的 JFrame 这是我正在处理的源代码 private static void createFra
  • jquery自动完成颜色变化

    I am using bootstrap for UI and jquery custome UI for autocomplete When suggested items are listed i would like to match
  • SFML 绘制像素阵列

    我找到了这个 http lodev org cgtutor raycasting html http lodev org cgtutor raycasting html 互联网上的教程 我很感兴趣并想自己制作 不过我想在 SFML 中做到这
  • 什么才是真正性能更高的? Haskell 或 OCaml [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 使用复选框回发带有标志的枚举

    我有一个枚举属性 我试图通过复选框设置它的值 枚举被标记 当用户选择多个选项时 我希望该属性将所有选定的标记连接起来 我尝试为每个枚举值添加一个复选框 并为每个复选框指定相同的名称 在回发期间 将检索第一个选定的标志 但不会与其他标志连接
  • 防止 DataGrid 滚动对齐行

    我有一个 DataGrid 其中每一行都包含一个 ItemsControl 因此 网格的行可能会非常高 如果一行比网格的高度高 我无法滚动查看该行的其余部分 因为 DataGrid 会自动滚动到下一行 也就是说 如果我正在查看第 1 行的上
  • 将参数传递给 std::thread 包装器

    我想实现一个小型线程包装器 它提供线程是否仍处于活动状态或者线程是否已完成其工作的信息 为此 我需要将线程类要执行的函数及其参数传递给另一个函数 我有一个简单的实现 应该可以工作 但无法编译它 而且我不知道该怎么做才能使它工作 这是我的代码
  • Symfony2 - 获取 TWIG 模板中的当前 URL 或路由?

    我的路线是 admin path admin defaults controller CatalogWebBundle Admin admin 如何在 PHP 模板中获取路由名称 获取当前 URL request gt getRequest
  • Postgres 中左连接分页

    Summary 我的数据库中有需要在客户端显示的数据 到目前为止 它还没有被分页 但现在数据已经增长到明显减慢连接速度的程度 所以我想分页它 Setup 客户端我正在使用 DataTables 服务器端我使用 F 数据库是postgres
  • 一段时间后未调用 CLLocationManager didUpdateToLocation

    我正在尝试记录用户随时间的位置 如果用户在移动 则它可以正常工作 并且委托方法 didUpdateToLocation 会被可靠地调用 但是 如果用户静止并且应用程序在后台运行 那么在一段时间后 将不再调用委托方法 要重新启动它 需要将该应
  • 带参数的 Typescript 工厂模式

    我目前在我的项目中使用工厂模式 下面是最小的可重现代码 class A constructor public name string class B constructor public age number public address