typescript 使用多态的类类型作为没有any类型的类工厂的参数?

wz3gfoph  于 2023-03-31  发布在  TypeScript
关注(0)|答案(1)|浏览(111)

文档描述了如何在类工厂方法中使用类类型:

function create<Type>(c: { new (): Type }): Type {
  return new c();
}

这是一种非常常见的方法,但缺少构造函数参数。因此,通常类类型扩展如下:

function create<Type>(c: { new (...args: any[]): Type }): Type {
  return new c();
}

这很好用,但是使用了any关键字,我想避免使用。在一个具体的例子中,我创建了一个构造函数类型:

export type SymbolConstructor<T extends BaseSymbol> = new (...args: unknown[]) => T;

我想创建的类有不同的构造函数参数,所以我需要这个rest参数。
然而,这只是部分工作。在库(一个节点模块)中,我定义了一切正常。在一个类中,我有这样的方法:

public addNewSymbolOfType<T extends BaseSymbol>(t: SymbolConstructor<T>,
        parent: ScopedSymbol | undefined, ...args: unknown[]): T {

        const result = new t(...args);
        if (!parent || parent === this) {
            this.addSymbol(result);
        } else {
            parent.addSymbol(result);
        }

        return result;
    }

并且是这样使用的:

symbolTable.addNewSymbolOfType(FieldSymbol, classSymbol, `myField`);

其中FieldSymbol是从BaseSymbol派生的类,并且工作良好(在模块的单元测试中)。
在一个有这个节点模块作为依赖的项目中,我做了同样的事情:

const s = symbolTable.addNewSymbolOfType(FieldSymbol, mainSymbol, member);

但现在我得到一个错误:
“类型'typeof FieldSymbol'的参数不能分配给类型'SymbolConstructor'的参数。
构造签名的类型不兼容。
键入“new(名称:字符串,值:未知,类型?:类型|undefined)=〉FieldSymbol'不可赋值给类型'new(...args:unknown[])=〉FieldSymbol'.
参数“name”和“args”的类型不兼容。
类型“unknown”不能分配给类型“string”。
当我使用any作为构造函数参数时,这种情况也有效。
如果要使用unknown而不是any,正确的方法是什么?

w8f9ii69

w8f9ii691#

我草拟了一个简化版本的API,请参阅typescript playground,它看起来对类型很满意。关键是Args extends unknown[]在签名中有自己的泛型位置。

export type SymbolConstructor<
  T extends BaseSymbol,
  Args extends unknown[]
> = new (...args: Args) => T;

interface ScopedSymbol {
  addNewSymbolOfType: <T extends BaseSymbol, Args extends unknown[]>(
    c: SymbolConstructor<T, Args>,
    ...args: Args
  ) => T;
}

interface BaseSymbol {
  kind: symbol;
}

class DefaultScopedSymbol implements ScopedSymbol {
  children: BaseSymbol[] = [];

  addNewSymbolOfType<T extends BaseSymbol, Args extends unknown[]>(
    c: SymbolConstructor<T, Args>,
    ...args: Args
  ): T {
    const child = new c(...args);
    this.children.push(child);
    return child;
  }
}

相关问题