Setters
Clase 8 de 25 • Curso de TypeScript: Programación Orientada a Objetos y Asincronismo
Contenido del curso
Axel Enrique Galeed Gutierrez
Ronaldo Delgado
Katerin Calderón
carlos pino
Migdualy Alejandra Gonzalez Martinez
Reinaldo Mendoza
Jordy Mairena Montoya
Andrés Muñoz
Luis Enrique Mena Colín
Vladimir Farrera Vera
Alejandro Chavez
Iván Darío Sánchez Jiménez
Walter Omar Barrios Vazquez
Eminson Mendoza
Brahyan Antonio Martinez Madera
Juan Manuel Luna Blanco
Jhonatan Andres Mejia Ramirez
Ronaldo Delgado
Samuel Miranda Martínez
Miguel Angel Reyes Moreno
Les comparto mis apuntes. :D
Set
Es parecido a un get, solo que este no retorna nada, es un método void, pero no hace falta colocarle lo que retorna, ya que va a dar error.
A set lo podemos usar para tener reglas de modificación para nuestros parámetros.
Sintaxis
class ClassName { constructor () { statements } set methodName () { statements } }
genial
There are some principles to improve yor code and make it cleaner. One thing you can do better is to avoid the use of Else, so a simple solution for a code that requires an else is to validate first the scenario that throw the error and then assign the value, in the example of Nicolas it would stay like this:
set month(newValue: number) { if(newValue < 1 || newValue > 12 ){ throw new Error ("The month needs to be a number between 1 and 12") } this._month = newValue; }
that's interesting 🤔
el get y set dan interacción como si fueran una propiedad
pero nos hace modificar la propiedad para que no choquen, me parece mejor el método "normal" gatAlgo(){...}
Getters and setters
export type formatDate = 'days' | 'months' | 'years'; class MyDate { private _year: number; private _month: number; private _day: number; private _leapYear: boolean = false; // by deafault the year is not leap year private _months: { [key: number]: string; } = { // dictionari months of the year 1: 'January', 2: 'February', 3: 'March', 4: 'April', 5: 'May', 6: 'June', 7: 'July', 8: 'August', 9: 'September', 10: 'October', 11: 'November', 12: 'December' }; private _month31: number[] = [1, 3, 5, 7, 8, 10, 12]; // list of months that have 31 days constructor(year: number, month: number, day: number) { this._year = this._validYear(year); this._validLeapYear() this._month = this._validMonth(month); this._day = this._validDay(day); } printFormat(format: string = 'dd / nm / yy'): string { if (this._validError() == null) { // if validError returns null then there are no errors let day: string = this._addPadding(this._day); let month: string = this._addPadding(this._month); format = format.replace('yy', this._year.toString()); format = format.replace('dd', day); format = format.replace('mm', month); format = format.replace('nm', this._months[this._month]); return format; } else { return this._validError()!; // notation ! tells typescript that the programmer is in control } } // override toString(): string { return this.printFormat(); } get day(): number { return this._day; } set day(num: number) { this._day = this._validDay(num); } get month(): number { return this._month; } set month(num: number) { this._month = this._validMonth(num); this._day = this._validDay(this._day); // this line verifies the assigned values setters } get monthName(): string { return this._months[this._month]; } get year(): number { return this._year; } set year(num: number) { this._year = this._validYear(num); } get leapYear(): boolean { return this._leapYear; } private _validError(): string | null { // if any attribute has the value of zero then it is out of range and there is an error let error: string = '#outRange!'; // out of tange error indicator if (this._year == 0) { return `${error} year`; // error message } if (this._month == 0) { return `${error} month`; // error message } if (this._day == 0) { return `${error} day`; // error message } return null; // whithout errors } private _addPadding(num: number): string { if (num < 10) { return `0${num}`; } return num.toString(); } private _validYear(year: number): number { // if the year is greater than zero it is valid if(year > 0) { return year; } else { return 0; } } private _validDay(day: number): number { // validate the day if (day > 0) { if (this._month === 2) { // if the month is february let evaluateDay: number = 28; if (this._leapYear) { // if leap year evaluateDay++; } if (day <= evaluateDay) { return day; } else { return 0; } } else { // if it is any month except february let evaluateDay: number = 30; if (this._month31.includes(this._month)) { // if the month has 31 days evaluateDay++; } if (day <= evaluateDay) { return day; } else { return 0; } } } else { return 0 } } private _validMonth(month: number): number { // Validated that the month is between 1 and 12 if (month > 0 && month < 13) { return month; } else { return 0; } } private _validLeapYear(): void { /** * @ Check if the year is a leap year */ let result: number; result = (this._year / 4) % 2; // formula if ((n/4) % 2 == 0) if(result == 0) { this._leapYear = true; } } add(amount: number, format: formatDate): void { if (this._validError() == null) { if (format == 'days') { for (let i = 0; i < amount; i++) { this._day += 1; if (this._validDay(this._day) == 0) { // Validated the day based on the month and year /* if _validDay returns 0 the valid days for the current month were exceeded then the month is increased and day is restarted */ this._month++; if (this._month == 13) { this._year++; this._month = 1; } this._day = 1; } } } else if (format == 'months') { for (let i = 0; i < amount; i++) { this._month++; if (this._month > 12) { this._year++; this._month = 1; } } } else if (format == 'years') { if (amount > 0) { this._year += amount; } } } } } const myDate = new MyDate(2000, 2, 29); console.log(myDate.printFormat('dd of nm of yy')); myDate.add(3, 'days'); console.log(myDate.printFormat()); myDate.add(40, 'months'); console.log(myDate.printFormat('mm-dd-yy')); console.log(myDate.toString()); console.log(myDate.day); console.log(myDate.month); console.log(myDate.monthName); console.log(myDate.year); myDate.day = 31; myDate.year = 2000; myDate.month = 2; console.log(myDate.day); console.log(myDate.toString());
¿Por qué el throw new Error no lanzo un error en la consola ?
Sí sale el error. Yo cambié la condición de la siguiente manera:
set month(newValue: number) { if(newValue < 1 || newValue > 12) throw new Error('Invalid month') this._month = newValue; }
quita el new Error
public set month(newValue : number) { if (newValue >= 1 && newValue <= 12) { this._month = newValue }else{ throw ("month out of range"); } }
Ya que estamos en TS, podríamos también crear un tipo para month, de manera que solo puedan asigarse valores predefinidos en el tipo ¿no?
Les comparto mi código implementando tratamiento de errores.
export class MyDate { constructor( public year: number = 1984, public _month: number = 6, private _day: number = 26) {} printFormat(): string { const day = this.addPadding(this._day); const month = this.addPadding(this._month); return `${this.year}/${month}/${day}`; } private addPadding(value: number) { if (value < 10) { return `0${value}`; } return `${value}`; } public add(amount: number, type: 'days' | 'months' | 'years') { if (type === 'days') { this._day += amount; } if (type === 'months') { this._month += amount; } if (type === 'years') { this.year += amount; } } get day() { return this._day; } get isLeapYear(){ if(this.year % 400 === 0) return true if(this.year % 100 === 0) return false return this.year % 4 === 0 } get month(){ return this._month } set month(value: number){ try{ if(value >= 1 && value <= 12){ this._month = value } else{ throw new Error('month out of range') } } catch(e){ const error = (e as Error).message; console.log(error) } } } const newDate = new MyDate(2004, 3, 9); console.log(newDate.month) const newDate2 = new MyDate(2004, 3, 9); newDate2.month = 11 console.log('(11)=>',newDate2.month) const newDate3 = new MyDate(2004, 3, 9); newDate3.month = 25 console.log('(error',newDate3.month) console.log('With error handling')
El tipo de retorno del get debe ser asignable con el tipo de entrada para el set, es decir:
get month(): number {} set month(value: number) {}
No podría tener un get de la siguiente forma:
get month(): string { return this.addPadding(this._month) }
Los setters en TypeScript son métodos especiales utilizados para establecer el valor de una propiedad de una clase. Permiten validar o transformar los datos antes de asignarlos. Aquí tienes un ejemplo:
class Persona { private _edad: number; set edad(valor: number) { if (valor < 0) { console.error("La edad no puede ser negativa."); } else { this._edad = valor; } } get edad(): number { return this._edad; } } const persona = new Persona(); persona.edad = 30; // Establece la edad console.log(persona.edad); // Muestra 30 persona.edad = -5; // Lanza un error
Esto ilustra cómo los setters pueden ser útiles para controlar la asignación de propiedades.
Algo que me parece interesante es que los setters no se ejecutan como una funcion sino como una igualdad directamente
rango de meses no era entre 0 y 11??, entonces porque usaste entre 1 y 12?
El explico hace algunas clases que los meses eran de 0 a 11 en el Date de js pero como esta es nuestra propia clase MyDate ibamos a manejarla de 1 a 12.
Excelente video ahora me queda claro los setters y los getters
Estas reglas también funcionan para los métodos internos, como el add 🤯🤯🤯.
public add(amount: number, type: 'days' | 'months' | 'years') { if (type === 'days') { this.day += amount; } if (type === 'months') { this.month += amount; } if (type === 'years') { this.year += amount; } }
Setters
Los setters DEBEN ser void.
set month(newMonth: number) { if (newMonth < 1 || newMonth > 12) { throw new Error('Invalid month'); } this._month = newMonth; }
const anotherDate = new MyDate(2024, 1, 1); anotherDate.month = 5; //anotherDate.month = 50; //! Error