typescript: How to annotate a type that's a class (instead of a class instance)?

Viewed 432

Let's assume there is a model class like:

export abstract class Target {
    id!: number;
    name!: string;
}

export class Target1 extends Target {
    name = 'target1';
    id: number;
    kind: string;

    constructor(id: number, kind: string) {
        super();
        this.id = id;
        this.kind = kind;
    }
 
    static getForm(){
      return new FormGroup({...});
    }
}

export class Target2 extends Target {
    name = 'target2';
    id: number;
    address: string;

    constructor(id: number, address: string) {
        super();
        this.id = id;
        this.address = address;
    }

    static getForm(){
       return new FormGroup({...});
    }
}

....
export class TargetN extends Target {}

type Measure = {
    type: string;
    target: any; // Here is what I need to correct the type
}

const measures: Measure[] = [
    { type: 'measure1', target: Target1},
    { type: 'measure2', target: Target2},
    ...
    { type: 'measureN', target: TargetN},
];

In the form, I allow user input address or kind based on situation user selected measures.type then I will instance a new target as bellow:

const inputValue = 'http://localhost:3000';
const selectedType = measures[0].type;
const measure = measures.find(m => m.type === selectedType)!;
const target = new measure.target(1, inputValue);
const form = measure.target.getForm();
console.log(target.kind); // 
...

Everything is working fine. But which annoys me is that I don't know how to put the correct type at Measure -> target instead of any:

type Measure = {
    type: string;
    target: any; // ??? 
}

If I give it a type Target like bellow:

type Measure = {
    type: string;
    target: Target;
}

then I will get the error

 Did you mean to use 'new' with this expression?

And, if I give it typeof like bellow:

type Measure = {
    type: string;
    target: typeof Target;
}

then I will get the error

 Type 'typeof Target1' is not assignable to type 'typeof Target'.

How can I replace type any in target with another specificity type?

If I use ThisType it looks good

type Measure = {
    type: string;
    target: ThisType<Target>;
}

but the static method inside Target1 or Target2 it will throw error

Property 'getForm' does not exist on type 'ThisType<Target>'.

I also tried with Required like below:

type RequiredTarget = Required<typeof Target>;
type Measure = {
    type: string;
    target: RequiredTarget;
}

but it's not working too.

I appreciate your help with that.

1 Answers

I would approach this with the following manner:

    type S = string;
    type I = number;

    interface IY {
        type?: string;
        target?: S | I;
    }

    type Y = IY

    const U: Y = { type: "U", target: "1" }
    const V: Y = { type: "V", target: 2 }
    const X: Y = {}
Related