Tengo el siguiente código en el constructor de una clase (abreviado para el propósito de la pregunta):
constructor(effect: EffectInstance, names: string[], count?: number) { this.effect = effect; // instance of a class "Effect" let name; for (name of names) { this.custom.set(name, this.effect); // custom: Map } }
EffectInstancees el tipo de esta clase, que es genérica
Cuando cambio this.effect.name en un método de la clase, o cuando tomo el efecto del Map this.custom y cambio su nombre, ambos cambian.
Por lo que puedo decir, esto se debe al comportamiento de paso por referencia de JavaScript con los objetos, ya que estoy 100% seguro de que no estoy modificando los valores que no quiero modificar. (Me gustaría poder cambiar el nombre de la instancia de Efecto en el Mapa custom , pero mantener this.effect.name sin cambios)
Traté de volver a crear instancias de las clases con los parámetros en constructor() , pero esto plantea un nuevo problema: estaría perdiendo tipos y parece que no puedo encontrar la manera de solucionar esto. Esto es lo que probé:
( EffectInstance , para referencia: <EffectInstance extends Effect> )
constructor(effect: EffectInstance, names: string[], count?: number) { this.effect = effect; let altEffect = effect instanceof PlayerEffect ? new PlayerEffect(effect.name, effect.ignoreRaces) : new Effect(effect.name); let name; for (name of names) { this.custom.set(name, altEffect); } } Al hacerlo, TS genera este error en altEffect :
TS2345: Argument of type 'Effect' is not assignable to parameter of type 'EffectInstance'. 'Effect' is assignable to the constraint of type 'EffectInstance', but 'EffectInstance' could be instantiated with a different subtype of constraint 'Effect'.Necesito detener el comportamiento de paso por referencia o conservar el tipo que contiene EffectInstance. ¿Cómo puedo hacer esto?
La mayoría de los lenguajes pasan objetos por referencia, por lo que este no es un comportamiento único con javascript.
Si desea pasar una copia de la instancia de clase y no la instancia original y enviar el clon donde no desea enviar la instancia original.
class Car { constructor(name) { this.name = name; } } let orignalClass = new Car('BMW'); let cloneClass = Object.assign(Object.create(Object.getPrototypeOf(orignalClass)), orignalClass) console.log(orignalClass); console.log(cloneClass); // now both can be updated individually orignalClass.name = 'BMw-1'; cloneClass.name = "BMW-copy" console.log("after update"); console.log(orignalClass); console.log(cloneClass);a través de su código, este tipo personalizado debe ser Efecto.
constructor(effect: EffectInstance, names: string[], count?: number) { this.custom = new Map<string, Effect>(); // altEffect type could be PlayerEffect or Effect this.effect = effect; let altEffect = effect instanceof PlayerEffect ? new PlayerEffect(effect.name, effect.ignoreRaces) : new Effect(effect.name); let name; for (name of names) { this.custom.set(name, altEffect); } }