Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript - type to represent any class?

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.)

like image 911
Ondra Žižka Avatar asked Oct 11 '16 11:10

Ondra Žižka


1 Answers

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)

like image 188
Nitzan Tomer Avatar answered Oct 20 '22 22:10

Nitzan Tomer