Búsqueda de sitios web

typescript - ¿Hay una manera elegante de establecer una propiedad de clase solo una vez?


En TypeScript, mientras se está en una clase, ¿hay una manera elegante de establecer un valor solo una vez? En otras palabras, ¿existe un equivalente a establecer un valor como readonly después de asignarle un valor?

Por ejemplo:

class FooExample {
    public fixedValue: string;

    public setFixedValue(value: string): void {
        if (!this.fixedValue) {
            // this value should be immutable
            this.fixedValue = value;
        }
    }
}

No estoy buscando un getter, porque la propiedad de la clase podría ser cambiada dentro de la propia clase.

Respuesta #1

Después de leer las respuestas sugeridas y hacer mi propia investigación, creo que he encontrado la solución más elegante. Primero defines el valor como un Object y luego aplicas freeze() al Object después de poblar la propiedad relacionada.

class FooExample {
    public fixedValue = {
        value: '';
    };

    public setFixedValue(value: string): void {
        if (!Object.isFrozen(this.fixedValue)) {
            this.fixedValue.value = value;
            Object.freeze(this.fixedValue);
        }
    }
}

Respuesta #2

Podrías usar un setter "inteligente" para lograr esto. La idea es definir un setter en la clase, eliminar el setter desde dentro de sí mismo y definir una propiedad de solo lectura a través del método Object.defineProperty llamado con el descriptor cuya propiedad writable está establecida en false.

La parte de "cambiado dentro de la propia clase" podría lograrse mediante otra redefinición de propiedad. No olvides hacer que la propiedad sea configurable desde el principio.

Aquí está cómo podría verse todo (no creo que haya una forma más elegante de hacer esto): la versión en tiempo de ejecución de la respuesta no es específica de TypeScript:

class ReadonlyFields {
  set fixed(value) {
    Object.defineProperty(this, "fixed", {
      value,
      writable: false,
      configurable: true,
    });
  }

  doSomething() {
    Object.defineProperty(this, "fixed", {
      value: 24, //exact logic for changing the value is up to you
      writable: false
    });
  }
}

const r = new ReadonlyFields();
r.fixed = 42;
console.log(r.fixed); //42;
r.fixed = 24;
console.log(r.fixed); //42;
r.doSomething();
console.log(r.fixed); //24;

Si también quieres hacer cumplir esto desde el punto de vista del sistema de tipos, simplemente haz que la propiedad sea readonly:

class ReadonlyFields {
  readonly fixed!: number;

  setFixed(value: number) {
    Object.defineProperty(this, "fixed", {
      value,
      writable: false,
      configurable: true,
    });
  }

  doSomething() {
    Object.defineProperty(this, "fixed", {
      value: 24, //exact logic for changing the value is up to you
      writable: false,
    });
  }
}

const r = new ReadonlyFields();
r.setFixed(42); //OK
//@ts-expect-error
r.fixed = 24;
r.doSomething(); //OK

Artículos relacionados