首页 文章

返回扩展匿名类的函数的类型定义

提问于
浏览
1

我试图创建一个函数,它接受一个类作为参数(不是类实例,而是类本身),并返回另一个扩展参数中给出的类的类 .

我试着定义typescript函数如下,我得到以下错误: Type 'typeof (Anonymous class)' is not assignable to type 'T'

function extendClass<T>(base: T): T  {
    return class extends base{
    };
}

我上面函数的示例用法:

class A {
}

const B = extendClass(A); // B is an extended class of A

let b = new B(); // b is instance of class B

extendClass函数的正确类型定义是什么?

2 回答

  • 1

    您需要确保传递给 extendClass 的参数是一个类,而不是一个实例 . 在类型级别,类可以表示为新函数:

    new (...args: any[]) => any
    

    为了使其更具可读性,让我们给它一个别名 .

    interface Constructable {
        new (...args: any[]): any;
    }
    

    现在我们拥有了所需的一切!

    function extendClass<T extends Constructable>(Base: T) {
        return class extends Base {};
    };
    

    但是,返回类型手动编写有点麻烦,因为它需要同时处理返回类的类型和原型链 . 我们可以使用类型推断为我们完成工作:

    function extendClass<T extends Constructable>(BaseClass: T): typeof DerivedClass {
        const DerivedClass = class extends BaseClass {};
    
        return DerivedClass;
    }
    

    派生类被分配给局部变量,因此我们可以读取并使用其推断类型 .

  • 1

    您需要指定 T 是一个构造函数,以便能够将其用作函数中的匿名类的基类 . 关于返回类型,我的建议是让编译器推断出这个 . Ť

    如果匿名类没有添加您想要从函数外部访问的成员,则可以使用 T 作为返回类型,但是如果添加成员,只需让编译器推断 .

    function extendClass<T extends new (...a: any[])=> any>(base: T)  {
        return class extends base{
        };
    }
    class A {
    }
    
    const B = extendClass(A); // B is an extended class of A
    type B = InstanceType<typeof B>
    
    let b:B = new B(); // b is instance of class B
    

    如果您不添加公共成员,则可以使用 T 作为返回类型:

    export function extendClass<T extends new (...a: any[]) => any>(base: T): T {
        return class extends base {
        }
    }
    

    如果您保留推断的版本并生成声明,您实际上可以看到如果我们将成员添加到 T ,将如何显式声明返回类型:

    export function extendClass<T extends new (...a: any[]) => any>(base: T): {
        new (...a: any[]): {
            test(): void;
        };
    } & T {
        return class extends base {
            test() { }
        }
    }
    

    您可以在代码中使用此类型,它应该按预期工作 .

相关问题