Uso un objeto Proxy con la idea de que cada vez que se actualiza una propiedad, también se puede iniciar algún otro efecto secundario. No quiero iniciar los efectos secundarios en los muchos lugares donde se establecen las propiedades ( principio SECO ).
Código de ejemplo algo artificial:
const session = new Proxy( { id: undefined as number, age: undefined as number}, // =target { set: (target, property, value): boolean => { switch (property) { case 'id': { target[property] = value; this.notifyIdWasUpdated(value); return true; } case 'age': { target[property] = value; this.updateAgeDisplay(value); return true; } default: { return false; } } } } ); Mi problema es que cuando uso la refactorización de mi IDE para cambiar un nombre de propiedad (clave) del objeto de target (por ejemplo, age ), las constantes de cadena en las declaraciones de case (por ejemplo 'age' ) no se actualizan también (lo que podría causar un insecto).
Pregunta: ¿Hay alguna manera de obtener dinámicamente un valor de cadena 'key' de una expresión obj.key en la declaración del case (que luego sería una prueba de refactorización)? ( Algo así como el inverso del ['key'] , en cierto modo...) Alternativamente, ¿puede sugerir otra forma de estructurar el código anterior para protegerse contra este tipo de supervisión del programador?
Puedes intentar usar keyof aquí.
interface Session { id: number age: number } const session1 = new Proxy( { id: 0, age: 0 } as Session, { set: (target, property: keyof Session, value): boolean => { switch (property) { case 'id': { target[property] = value; this.notifyIdWasUpdated(value); return true; } case 'age': { target[property] = value; this.updateAgeDisplay(value); return true; } default: { return false; } } } } ); Esto no se renombrará automáticamente, pero TypeScript mostrará un error si la propiedad en case de que no exista en Session .
El siguiente caso debería permitir el cambio de nombre automático:
interface Session { id: number age: number } type Handlers<Model> = { [Key in keyof Model]: (newValue: Model[Key]) => void; } // Partial<Handlers<Session>> in case you don't want to handle each property const handlers: Handlers<Session> = { id: () => { }, age: () => { }, } const session = new Proxy( { id: 0, age: 0 } as Session, { set: (target, property: keyof Session, value): boolean => { const handler = handlers[property]; if (handler) { handler(value) return true; } return false; } } );Aunque se eligió otra respuesta , el problema con el código de ejemplo dado se encuentra en un nivel de abstracción algo más alto. Dado que el objeto de session encapsula una serie de propiedades, el objeto de session debe manejarse como una unidad y no las propiedades por separado. (Probablemente haya un nombre de olor en código o alguna otra advertencia contra esto...)
La muestra entonces sería simplemente:
session = new Proxy( { id: undefined, age: undefined}, // =target { set: (target, property, value): boolean => { if (typeof property === 'string' && Object.keys(target).includes(<string>property)) { target[property] = value; doSideEffects(target); return true; } else { return false; } }, } );Esto simplifica el controlador en el Proxy.
(Soy el OP. En mi caso, ahora también ha simplificado considerablemente el código de efectos secundarios. Supongo que el efecto del patito de goma entró en juego...)
La solución simple sería algo como esto:
function nameof<TType>(selector: (t?: TType) => any) { const match = selector .toString() .match(/=>\s*(?:[a-zA-Z0-9_$]+\.?)*?([a-zA-Z0-9_$]+)$/); if (match) { return match[1]; } return undefined; } interface MyType { id: any; age: number; } const session = new Proxy( { id: undefined as number, age: undefined as number }, // =target { set: (target, property, value): boolean => { switch (property) { case nameof<MyType>((t) => t.id): { target[property] = value; this.notifyIdWasUpdated(value); return true; } case nameof<MyType>((t) => t.age): { target[property] = value; this.updateAgeDisplay(value); return true; } default: { return false; } } }, } ); NOTA: ¡Cuidado, si apuntas a ES5! La función de flecha se convierte en una función regular con return para que la expresión regular no funcione, debe cambiar la expresión regular.