10
votes

What type should I use in typescript to represent any class?

I'm trying to write a function that takes an array of classes and returns an array with different order.

function shuffle(classes: typeof Object[]) : typeof Object[] {
    return ...;
}

class A { }
class B extends A { }
class C extends B { }
class D extends B { }
suffle([A, B, C, D]);

Argument of type 'typeof A[]' is not assignable to parameter of type 'ObjectConstructor[]'.

Then I've tried:

shuffle([typeof A, typeof B, typeof C, typeof D]);

error TS2345: Argument of type 'string[]' is not assignable to parameter of type 'ObjectConstructor[]'. Type 'string' is not assignable to type 'ObjectConstructor'.

What's the right way? Generics? How? This doesn't work:

export function <T extends typeof Object> shuffle(classes: T[]) : T[]

This neither:

export function <T extends Object> sortClassesBySpeciality(classes: typeof T[]) : typeof T[]

Also why typeof (typeof A) is "string" and "" + typeof A is function? Ok, got this, typeof has two very different meanings context of type definition and expression.

(The ultimate goal is to sort the classes by level of extends from Object.)

1

1 Answers

11
votes

You should avoid using the type Object in typescript, you better use any as the docs say:

You might expect Object to play a similar role, as it does in other languages. But variables of type Object only allow you to assign any value to them - you can’t call arbitrary methods on them, even ones that actually exist

But if you want to represent classes then you need to have the following form:

{ new (): CLASS_TYPE }

Or in your case:

function shuffle(classes: Array<{ new (): any }>): Array<{ new (): any }> {
    return [];
}

class A { }
class B extends A { }
class C extends B { }
class D extends B { }
shuffle([A, B, C, D]);

(code in playground)

If all of your classes are based on a super class (as your example implies) then you can simply do:

function shuffle(classes: Array<{ new (): A }>): Array<{ new (): A }> {
    return [];
}

Edit

Just saw that you want to

sort the classes by level of extends from Object

To answer that:

function shuffle(classes: Array<{ new (): any }>): Array<{ new (): any }> {
    return classes.sort((a, b) => getInheritanceLevel(a) - getInheritanceLevel(b));
}

function getInheritanceLevel(cls: { new (): any }): number {
    let level = 0;

    while (Object.getPrototypeOf(cls.prototype) !== Object.prototype) {
        level++;
        cls = Object.getPrototypeOf(cls.prototype).constructor;
    }

    return level;
}

shuffle([D, A, C, B]); // returns [A, B, D, C]

(code in playground)