Búsqueda de sitios web

javascript - Forzando que las subclases sean inmutables


Tengo una clase base con algunas propiedades:

class Component {
    readonly id: number
    readonly type: number
}

Y me gustaría tener algunas subclases:

class HealthComponent extends Component {
    max_health: number,
    current_health: number
}

etc.

Lo que quiero es esencialmente que HealthComponent tenga el mismo comportamiento que un Immutable.Record:

const health = HealthComponent(100, 100);
health.max_health = 40; // Shouldn't work
const new_health = new HealthComponent(40, health.current_health); // Works

Todas las clases son solo datos; sin comportamiento (si hay algún comportamiento, estará en métodos estáticos, no en métodos de instancia). Ahora quiero hacer cumplir tanto como sea posible que las subclases sean inmutables (en el sentido de que se permiten modificaciones, pero hacer cambios resulta en un nuevo objeto o lanza un error al estilo de Immutable.js) y no puedo averiguar la mejor manera de hacer esto.

Lo mejor que se me ha ocurrido es simplemente hacer que cada subclase tenga un miembro de solo lectura data que sea un Immutable.Record con los campos apropiados, pero incluso esto no es del todo correcto porque cambiarlo devolvería un nuevo objeto data, y realmente quiero un objeto Component completamente nuevo, y esto tampoco garantiza realmente que todos los componentes sigan esta convención.

La otra cosa que he considerado es hacer que la clase base sea un Immutable.Record con un campo data: Immutable.Map y luego las subclases proporcionen un Immutable.Map al constructor super con todas las claves, pero entonces la gente podría simplemente agregar nuevas claves de forma indiscriminada, lo cual tampoco es ideal.

¿Existe un patrón de diseño mágico que podría ayudarme aquí?

Respuesta #1

Usa el tipo mapeado Readonly.

class Component {
    constructor(public id: number, public type: number) {

    }
}

class HealthComponent extends Component {
    constructor(public id: number, public type: number, public max_health: number, public current_health: number) {
        super(id, type);
     }
}

let hc: Readonly<HealthComponent> = new HealthComponent(1, 2, 3, 4);
hc.max_health = 40; // Error

Considera usar una interface si no tienes comportamiento.

interface Component {
    id: number
    type: number
}

interface HealthComponent extends Component {
    max_health: number;
    current_health: number;
}

let hc: Readonly<HealthComponent> = {
    id: 1,
    type: 2,
    max_health: 3,
    current_health: 4
};

hc.max_health = 40; // Error