简体   繁体   中英

Dynamic class/interface in Typescript (w Angular)

I create an object with a dynamic class by param. Is there a way to specify also the type of that object to have the intellisense?

This is the code:

Main:

let ita: any = new DynamicClass('ITA');
let deu: any = new DynamicClass('DEU');

Class to create the dynamic class:

export class DynamicClass {
  constructor(className: string) {
    if (Store[className] === undefined || Store[className] === null) {
      throw new Error(`Class type of \'${className}\' is not in the store`);
    }
    return new Store[className];
  }
}

And my classes:

export class ITA {
  id: string;
  name: string;
  pck: string;

  constructor() {
    console.log('ITA class');

    this.id = '1';
    this.name = 'ita';
    this.pck = '4';
  }
}

export class DEU {
  id: string;
  name: string;
  size: string;

  constructor() {
    console.log('DEU class');

    this.id = '1';
    this.name = 'ita';
    this.size = '5';
  }
}

export const Store: any = {
  ITA,
  DEU,
}

You can cast it:

let ita: ITA = new DynamicClass('ITA') as ITA;
let deu: DEU = new DynamicClass('DEU') as DEU;

You could create factory function which will accept only known class names and its return type will be resolved according to provided key (class name):

const Store = {
    ITA,
    DEU,
} as const;

type ClassMap = typeof Store;

const createClass = <Key extends keyof ClassMap>(key: Key) =>
    new Store[key] as InstanceType<ClassMap[Key]>;

const instance = createClass('ITA'); // instance is of ITA type

createClass('foo'); // Error: '"foo"' is not assignable to '"ITA" | "DEU"'

Playground

I would suggest the following:

export const Store = {
  ITA,
  DEU,
};

let ita = new Store['ITA'];        // ita type inferred to ITA
let deu = new Store['DEU'];        // deu type inferred to DEU
let x = new Store['MISSING_PROP']; // does not compile

Playground

but I see no benefit over:

let ita = new ITA();
let deu = new DEU(); 

Update (after clarifying question)

Why don't you define union type for acepted languages, and use a switch statement:

type Langs = 'ITA' | 'DEU'

function doSth(lang: Langs): string { 
  switch (lang) {
    case 'ITA':
      const ita = new ITA();
      return ita.name;
    case 'DEU':
      const deu = new DEU();
      return deu.name + deu.size;
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM