Búsqueda de sitios web

objeto - typescript: definir el tipo de una colección de clases


No sé cómo definir el tipo de la colección de una clase en TypeScript:

Cuando compilo el siguiente código, obtengo un error:

    class Wall{
        brick: string;

        constructor(){
            this.brick = "jolies briques oranges";
        }

        // Wall methods ...
    }

class Critter {
    CritterProperty1: string[];
    CritterProperty2: string;

    constructor() {
        this.CritterProperty1 = "n ne e se s so o no".split(" ");        
    }

    // Critter methods ...
}

type legendObjectType = Critter | Wall;

interface Ilegend {
    [k: string]: legendObjectType; 
}

// i've got an issue to define the type of 'theLegend' Object
let theLegend: Ilegend = {
    "X": Wall,
    "o": Critter
}

error TS2322: El tipo '{ "X": typeof Wall; "o": typeof Critter; }' no se puede asignar al tipo 'Ilegend'.

mientras puedo compilarlo, si la "Clase Wall" está vacía.

¿Alguien sabe cómo definir el tipo de la colección de una clase así?

let theLegend={ "X": Wall, "o": Critter }

(este es un ejemplo del capítulo 7 de Eloquent JavaScript, luego intento transcribirlo en TypeScript)

EDITAR

Completo la respuesta de Rico Kahler, con una clase abstracta para evitar usar el tipo unión

abstract class MapItem {
    originChar: string;

    constructor(){}
}

class Wall extends MapItem {
    brick: string;

    constructor(){
        super();
        this.brick = "jolies briques oranges";
    }

    // Wall methods ...
}

class Critter extends MapItem {
    CritterProperty1: string[];
    CritterProperty2: string;

    constructor() {
        super();
        this.CritterProperty1 = "n ne e se s so o no".split(" ");        
    }

    // Critter methods ...
}

interface Ilegend {
    [k: string]: new () => MapItem; 
}

let theLegend: Ilegend = {
    "X": Wall,
    "o": Critter
}

gracias.

Respuesta #1

Tu problema radica en tu objeto theLegend.

Typescript espera una instancia de Wall o Critter, pero en su lugar le estás proporcionando un tipo.

let theLegend: Ilegend = {
    "X": Wall, // `Wall` is a type not an instance, it is `typeof Wall` or the Wall type
    "o": Critter // `Criter` is a type not an instance
}

Algo como lo siguiente funcionará:

let theLegend: Ilegend = {
    X: new Wall(), // now it's an instance!
    o: new Critter()
}

Editar:

Ahora leyendo las páginas de JavaScript que vinculaste, parece que me perdí tu intención. Si quieres crear una interfaz que tome un constructor, entonces yo escribiría Ilegend de la siguiente manera:

interface Legend {
    [k: string]: new () => (Critter | Wall)
}

// now you can define an object with this type

let legend: Legend = {
    // here `Critter` actually refers to the class constructor
    // that conforms to the type `new () => (Critter | Wall)` instead of just a type
    something: Critter,
    somethingElse: Wall
}

const critter = new legend.something() // creates a `Critter`
const wall = new legend.somethingElse() // creates a `Wall`

// however, the type of `critter` and `wall` are both `Critter | Wall`. You'd have to use type assertion (i.e. casting) because typescript can't tell if its either a Critter or a Wall

Ahora las interfaces permiten que cualquier cadena sea una clave y esperan que cada valor sea una función sobre la que puedas usar new para obtener ya sea un Critter o un Wall