如何将类注释到工厂函数转换器

时间:2018-02-08 22:22:47

标签: typescript generics

Typescript playground link

我正在尝试注释一个接受类的函数,并返回一个返回该类实例的工厂函数。 (基本上,它不需要new)。

以下是我提出的建议:

const noNew = <T, U = new (...a: any[]) => T>(clazz: U): { (...b: any[]): T } => {
    return (...args: any[]) => {
        return new clazz(...args);
    };
}

这至少有两个原因:

  1. 我得到一个“不能使用'new'的表达式,其类型缺少调用或构造签名。” return new clazz(...args);错误。
  2. 我没有得到构造函数参数参数的任何类型完成或类型检查。
  3. 我如何重写这不会产生错误并使参数具有类型感知功能?

1 个答案:

答案 0 :(得分:1)

第一个问题很容易修复,您实际上并不需要U只能使用clazz: new (...a: any[]) => T

第二个问题有点复杂,并没有一个完美的解决方案。要获取参数类型,您需要定义具有多个签名的函数,每个签名对应于构造函数参数列表的每个长度:

function noNew<T>(clazz: new () => T): { (): T } 
function noNew<T, T1>(clazz: new (arg1: T1) => T): { (arg1: T1): T } 
function noNew<T, T1, T2>(clazz: new (arg1: T1, arg2: T2) => T): { (arg1: T1, arg2: T2): T } 
function noNew<T, T1, T2, T3>(clazz: new (arg1: T1, arg2: T2, arg3: T3) => T): { (arg1: T1, arg2: T2, arg3: T3): T } 
function noNew<T>(clazz: new (...a: any[]) => T): { (...b: any[]): T } {
    return (...args: any[]) => {
        return new clazz(...args);
    };
}

用法:

class AA {
    constructor (){}
}

class BB {
    constructor (a: string){}
}

let d = noNew(AA)();
let b = noNew(BB)("");

除了有可选参数的情况之外,它有效,然后noNew返回一个只保留所需参数并删除可选参数的函数。

class BB {
    constructor (a?: string){}
}
let b = noNew(BB)(); // No arguments