Tengo una clase, por ejemplo:
class Team { pointsFor: number; pointsAgainst: number; constructor(){ this.pointsFor = 0; this.pointsAgainst = 0; } }
Ahora me gustaría crear un método para esta clase donde pueda actualizar la propiedad por clave, por ejemplo:
updateStats = (bool: boolean, property: string, increment: number) =>{ const key: keyof this = bool ? `${property}For` : `${property}Against` this[key] += increment }
Sin embargo, recibo un error de que la cadena no se puede asignar a la clave de esto, y si fuerzo el tipo como
const key: keyof this = bool ? `${property}For` as keyof this : `${property}Against` as keyof this
luego aparece un error: "El operador '+=' no se puede aplicar a los tipos 'this[keyof this]' y 'number'".
¿Hay alguna manera de lograr lo que quiero aquí donde llamo a team.updateStats(true, 'points', 2)
y actualizo pointsFor
?
Realmente no recomendaría usar la manipulación de cadenas con las propiedades de la clase TypeScript de la forma en que lo intenta.
Al usar keyof this
, esencialmente se está refiriendo a todas las claves de la clase, como pointsFor: number
, pointsAgainst: number
y updateStats: Function
. Como puedes ver, no todos son números.
Otro problema es que una string
puede ser cualquier cosa, por lo que updateStats(true, 'blah blah', 3)
podría volverse válido si TypeScript no lo detuviera.
Sería mucho mejor restringir las propiedades específicas que necesita a un objeto dentro de la clase con propiedades claramente definidas.
Por ejemplo:
class Team { teamProps: { [key: string]: { for: number, against: number }} = { points: { for: 0, against: 0 } } updateStats = (bool: boolean, property: keyof typeof this.teamProps, increment: number) =>{ this.teamProps[property][bool ? 'for' : 'against'] += increment; } }
Puede acceder a estas propiedades con <Team>.teamProps.points.for
en lugar de <Team>.pointsFor
.
Puede hacer casi todo con el sistema de tipos TypeScripts:
TeamProp
toma una unión de claves ( keyof this
en este caso) y devuelve solo cadenas, que coinciden con ${string}For
o ${string}Against
.
type TeamProp<K> = K extends `${infer P}For` ? P : K extends `${infer P}Against` ? P : never; class Team { pointsFor: number; pointsAgainst: number; constructor() { this.pointsFor = 0; this.pointsAgainst = 0; } updateStats<P extends TeamProp<keyof this>>(bool: boolean, property: P, increment: number) { const key = bool ? `${property}For` : `${property}Against` this[key] += increment } } const t = new Team() // Works t.updateStats(true, 'points', 1); // Argument of type '"foo"' is not assignable to parameter of type '"points"'. t.updateStats(true, 'foo', 1);