El conocimiento es el nuevo dinero.
Aprender es la nueva manera en la que inviertes
Acceso Cursos

Por qué evitar el uso de 'any' en TypeScript

· 7 min de lectura
Por qué evitar el uso de 'any' en TypeScript

Cuando creamos aplicaciones en Angular, el tipo any es nuestro "salvavidas" cuando nos enfrentamos a mensajes de error complejos, queremos ahorrar tiempo al no escribir definiciones de tipo específicas, o pensamos que la verificación de tipo de TypeScript limita nuestra flexibilidad y libertad de codificación.

Usar el tipo any puede parecer una solución fácil para problemas comunes, pero es importante que los desarrolladores piensen en los problemas ocultos y los efectos reales de usar este método simple.

Usar el tipo any con frecuencia puede debilitar accidentalmente el propósito principal de TypeScript, que es hacer que el código sea más seguro y encontrar errores temprano. Ignorar las ventajas de verificar tipos puede llevar a errores ocultos, código más difícil de mantener y código más complejo.

Hoy, mostraré algunas razones con ejemplos por las cuales evito usar any y en su lugar prefiero utilizar unknown. También discutiré cómo utilizar los tipos de utilidad de TypeScript para crear nuevos tipos flexibles. ¡Comencemos!

CPU
1 vCPU
MEMORIA
1 GB
ALMACENAMIENTO
10 GB
TRANSFERENCIA
1 TB
PRECIO
$ 4 mes
Para obtener el servidor GRATIS debes de escribir el cupon "LEIFER"

La seguridad del usar Typos

Cuando se elige el tipo any, puede parecer una solución fácil para problemas de tipado. Sin embargo, esta elección tiene un gran inconveniente: perdemos la seguridad de tipo, que es la característica principal de TypeScript para asegurar que nuestro código funcione correctamente.

Quiero mostrar los peligros de no considerar la seguridad de tipo con any y resaltar lo importante que es el sistema de tipos de TypeScript.

Considera el siguiente fragmento de código, donde tenemos el método accountBalance que espera una cuenta y una cantidad para actualizar el saldo.

export class Accounting {

  accountBalance(account: any, amount:any) {
    return account.balance += amount;
  }
}

Dado que el método accountBalance espera un tipo 'any' tanto para la cuenta como para la cantidad, puedo pasar los siguientes parámetros:

let accounting = new Accounting()
let balanceA = accounting.accountBalance({accountNumber: '05654613', balance: 15}, 26)    
let balanceB = accounting.accountBalance({accountNumber: '05654613', balance: 15}, '26')
console.log({balanceA, balanceB})

¿Es este el resultado esperado? ¿Por qué todo compila y parece funcionar bien, pero falla durante la ejecución?

Cuando trabajamos con TypeScript, esperamos que TypeScript, el IDE o el compilador nos adviertan sobre este tipo de problemas 🤦‍♂️.

¿Por qué el compilador no advierte sobre el problema? Creo que la solución más efectiva es introducir el tipo Account.

export type Account = {
  accountNumber: string;
  balance: number;
}

Cambia la firma de la función accountBalance para usar el tipo Account.

 accountBalance(account: Account, amount: number): number {
    return (account.total += amount);
  }

Con el tipado adecuado, el IDE, el compilador y la aplicación nos notifican sobre posibles problemas.

¡Perfecto! Ahora sabemos cómo utilizar la función y evitar errores durante la ejecución. Echemos un vistazo a otro escenario.

El IDE WebStorm y VSCode

Amamos TypeScript porque ofrece más que solo asistencia con el código; mejora Visual Studio Code y WebStorm al proporcionar funciones potentes como autocompletado, navegación de código y refactorización, todas las cuales dependen de los tipos de TypeScript.

Pero cuando usamos el tipo any, la seguridad de tipo y estas herramientas útiles. Veremos cómo usar any demasiado puede empeorar la codificación y cómo un buen tipado hace que tu código sea más seguro para la refactorización.

Por ejemplo, tenemos un método llamado updateAccount que acepta una cuenta de cualquier tipo, así como un objeto vacío.

account: any = {}
  DEFAULT_BALANCE = 3000

  updateAccount(account: any) {
    account.accountID = Math.random().toString();
    account.balance = this.DEFAULT_BALANCE;
    return account;
  }

Todo funciona bien, pero ¿qué sucede si quiero refactorizar 'accountNumber' a 'id' y 'balance' a 'total'?

Estoy utilizando las herramientas de refactorización en WebStorm para modificar los nombres de las variables, pero cuando cambio 'accountID' a 'id' y 'balance' a 'total', el IDE no realiza todos los ajustes necesarios.

Podemos resolver este problema cambiando el tipo de any a Account. Después de hacer este cambio, podemos proceder con confianza a la refactorización.

updateAccount(account: Account): Account {
    account.id = Math.random().toString();
    account.total = this.DEFAULT_BALANCE;
    return account;
  }

Podemos refactorizar una vez más, y el IDE capturará todo, asegurando un proceso fluido.

¿Y qué pasa con el objeto de cuenta? En lugar de usar 'any', cambiémoslo a 'Account'.

El IDE nos notificará que el objeto no está inicializado y también requerirá todas las propiedades de 'Account'.

DEFAULT_BALANCE = 3000;
  account: Account = {
    id: "DEFAULT_ID",
    total : this.DEFAULT_BALANCE
  }

Como puedes ver, usar 'any' puede ahorrar tiempo, pero a veces el precio a pagar no vale la pena.

¿Qué puedo hacer?

Quizás te preguntes, ¿qué puedes hacer cuando deseas tener flexibilidad? Entonces, cuando eso suceda, el tipo unknown es tu mejor amigo. Pero antes de introducir unknown, permíteme mostrar las diferencias entre any y unknown.

  • any permite cualquier operación, lo que puede llevar a errores en tiempo de ejecución.
  • unknown requiere una validación de tipo explícita antes de su uso.

Tipo Any

El tipo any te permite hacer cualquier cosa sin verificar los tipos, haciendo que TypeScript sea más flexible. Esto puede ser útil, pero también arriesgado, ya que puede causar errores difíciles de encontrar durante la ejecución del programa.

Ejemplo:

let riskyData: any = getDataFromAPI();
console.log(riskyData.name); // Compiles sin saber si riskData es una funcion o tiene la propiedad data.
riskyData(); 

En el ejemplo, TypeScript no emite advertencias sobre riskyData porque tiene el tipo "any". Esto puede causar errores si riskyData no tiene las características que pensamos que tiene.

Tipo Unknown

El tipo unknown es más seguro que any. Representa cualquier valor pero limita las acciones aleatorias en esos valores. Para usar un valor unknown, necesitas hacer comprobaciones específicas para conocer su tipo.

Ejemplo:

let safeData: unknown = getDataFromAPI();
console.log(safeData.name); // Error: Object is of type 'unknown'.
if (typeof safeData === 'string') {
   // we can perform because now TypeScript knows it’s a string.
    console.log(safeData.toUpperCase()); 
} else if (typeof safeData === 'object' && safeData !== null && 'name' in safeData) {
   // Safe, as we checked that 'name' is a property on safeData.
    console.log(safeData.name); 
}

En este ejemplo, TypeScript asegura que solo puedes usar la propiedad name o cambiar safeData a mayúsculas después de verificar su tipo. Esto ayuda a evitar errores asegurándose de que las acciones en los datos sean seguras.

Que pasa si no quiero crear un typo para cada caso?

Sé que a veces queremos crear un tipo con solo unas pocas propiedades, o nos falta alguna propiedad de Account; en estos casos, los tipos de utilidad de TypeScript pueden ayudarte.

Estos tipos de utilidad te ayudan a crear tipos a partir de otros, pero los que más uso son Pick y Omit, que son tipos de utilidad que ayudan a eliminar la necesidad de any:

  • Pick: Crea un tipo con propiedades seleccionadas de otro tipo. Ejemplo: type AccountID = Pick<Account, 'id'>;
  • Omit: Genera un tipo excluyendo propiedades específicas. Ejemplo: type AccountWithoutID = Omit<Account, 'id'>;

Resumen

Sé que usar "any" puede ser tentador, pero se debe abordar con precaución. Ahora que comprendemos las implicaciones y el precio a pagar al usarlo, creo que emplear alternativas como "unknown" y tipos de utilidad hará tu vida más fácil y resultará en un código base mejor.

Artículos Relacionados

Generando certificados SSL TOTALMENTE GRATIS
· 3 min de lectura
JSON.stringify() - Javascript
· 4 min de lectura