typescript - Hur man skickar en array av konstruktörer


Hur är det möjligt att skicka en array av funktioner som returnerar ett objekt av en viss typ. Med andra ord - en array av konstruktörer?

Det jag vill göra är något sådant här:

    constructor(name: string, systems: Array<Function>){
        this.system = new systems[0]();
    }

men jag fick ett fel Kan inte använda 'new' med ett uttryck vars typ saknar en anrops- eller konstruktorsignatur. och som jag förstår bör jag på något sätt låta kompilatorn veta vilken typ av objekt den konstruktorn returnerar men jag vet inte hur.

Med antagande av RJM's svar, här är ett lite utökat exempel på vad jag menar:

interface System{
    name: string;
}
interface Component{
    blahblha: string;
}
class Doh implements Component{
    blahblha: string;
}
class Bar implements System{
    name: string = 'bar';
} 

class Blah implements System{
    name: string = 'foo';
}
class Foo {
    systems: Array<System>;
    constructor(bars: Array<()=>System>) {
        for (let i in bars){
            this.systems.push(new bars[i]()); // error: only a void functions can be called with the 'new' keyword.
        }
    }
}
var foo = new Foo([Blah]); // error: Argument of type 'typeof Blah[]' is not assignable to parameter of type '(() => System[]'. Type 'typeof Blah[]' is not assignable to type '() => System'.

Jag vill försäkra mig om att Foo.systems bara kommer att fyllas med instanser av objekt som implementerar System-gränssnittet. Så jag borde få fel om jag gör något som new Foo([Doh]); men jag får fel även när jag skickar Blah

Svar #1

Om du vill instansiera klasser måste du hänvisa till dess konstruktor med hjälp av nyckelordet new.

function factory(constructors: { new (): System }[]) {
    let constructed = constructors.map(c => new c());
}

interface System {
    name: string;
}
class SomeClass implements System {
    name: string;
    constructor() { }
}

class SomeOtherClass implements System {
    name: string;
    constructor() { }
}

let a = factory([SomeClass, SomeClass, SomeClass, SomeOtherClass]);

Funktionen factory kommer att ta emot en lista över konstruktorer som kan skapa något som uppfyller System-gränssnittet.

Att anropa metoden med en klass som inte implementerar System kommer att resultera i det fel du får nu.

class AnotherClass {}
factory([AnotherClass]); // error

Strukturell typning fungerar också, så du behöver inte implementera gränssnittet uttryckligen.

class AnotherClass {
    name: string
}
factory([AnotherClass]);

För att göra koden lite renare kan du flytta gränssnittet som beskrivs för constructors-parametern till en interface-deklaration.

// an interface that describes classes that create instances that satisfy the System interface
interface CreatesSystem {
    new (): System
}

interface System {
    name: string;
}

function factory(constructors: CreatesSystem[]) {
    let constructed = constructors.map(c => new c());
}

Svar #2

Om du använder en lambda verkar det kompilera och köra utan problem.

function constructor(name: string, systems: Array<() => void>){
    this.system = new systems[0]();
}

Relaterade artiklar