Este artículo fue originalmente escrito en https://matiashernandez.dev
Typescript es un poderoso y expresivo lenguaje, que permite evitar que publiques bugs.
Recuerda, Typescript no es sólo un "super set" sobre Javascript, si no, es un lenguaje "Turing completo" en su sistema de tipos, es decir, puedes implementar complejos algoritmos usando sólo tipos.
Pero su poder reside en que tan bien expresas las restricciones de tu aplicación, es decir, como defines tus tipos.
Typescript te fuerza a pensar de una forma diferente al momento de implementar una solución. Debes pensar en como los datos fluyen a traves de tu programa y como esta información es transformada de "una forma a otra". Es decir, debes pensar en que tipos usarás.
Un tipo de dato que utilizamos constantemente es Array
.
Un arreglo permite trabajar con colecciones de datos de forma simple y eficiente.
Relacionados
Métodos de Arreglo: Array.every y Array.some
La guía definitiva de Métodos de Arreglos (escuela frontend)
Tanto en Javascript como en Typescript un arreglo puede ser inicializado tan sólo usando []
y puedes **definir su tipo **de similar forma o usando la forma genérica Array<T>
// Un arreglo que puede contener cualquier tipo y se inicializa vació
const arr: unknown[] = []
// Otra forma de definir el tipo
const arr2: Array<unknown> = []
// Un arreglo de strings inicializado con un elemento
const arr3: string[] = ['str']
¿Cómo evitar el uso de arreglos vacíos con Typescript?
Un arreglo puede entonces estar vacío o contener n
elementos.
Es tarea común verificar si un arreglo está o no vació para asi poder operar sobre él. ¿Cómo puedes determinar si un arreglo está vació?
En Javascript ésta tarea se realiza con un bloque condicional y revisando la propiedad .length
del arreglo.
Pero, ¿es posible utilizar el lenguaje de tipos de Typescript para evitar que un arreglo esté vacío sin tener que usar un condicional?
La idea aquí es permitir que Typescript revise el flujo de datos y nos muestre un error si estás tratando de acceder a un arreglo vacío.
Lo que harás será crear un nuevo tipo similar a Array
que te permite definir un arreglo que no puede ser vació por definición.
Llamemos a este tipo NonEmptyArray
.
type NonEmptyArray<T> = [T, ...T[]]
const emptyArr: NonEmptyArray<Item> = [] // error ❌
const emptyArr2: Array<Item> = [] // ok ✅
function expectNonEmptyArray(arr: NonEmptyArray<unknown>) {
console.log('Array no vacío', arr)
}
expectNonEmptyArray([]) // No puedes pasar arreglo vacío. ❌
expectNonEmptyArray(['algun valor']) // ok ✅
Así cada vez que requieras que, por ejemplo, el parámetro de una función sea un arreglo que no puede estar vacío, puedes usar NonEmptyArray
.
El único inconveniente es que ahora requerirás una función "type guard" ya que simplemente revisar si la propiedad lenth
de un arreglo no es 0, no lo transformará a ser tipo NonEmptyArray
function getArr(arr: NonEmptyArray<string>) {
return arr;
}
const arr3 = ['1']
if (arr3.length > 0)) {
// ⛔️ Error: Argument of type 'string[]' is not
// assignable to parameter of type 'NonEmptyArr<string>'.
getArr(arr3);
}
Este error ocurre por que getArr
espera que el argumento sea NonEmptyArray
pero arr3
es del tipo Array
.
Type guards
Una función "type-guard" te permite "ayudar" a Typescript a inferir correctamente el tipo de alguna variable.
Se trata de una sencilla función que retorna un valor boolean. Si este valor es true
entonces Typescript considerará que la variable evaluad es de un tipo u otro.
// Type Guard
function isNonEmpty<A>(arr: Array<A>): arr is NonEmptyArray<A>{
return arr.length > 0
}
Esta función recibe un arreglo genérico (por eso el uso de A
), y revisa si la propiedad length
es mayor que 0
.
Esta función esta marcada para retornar arr is NonEmptyArray<A>
es decir, que que el valor de la condición evaluad es true
Typescript entenderá que el parámetro utilizar arr
es del tipo NonEmptyArray
// Type Guard
function isNonEmpty<A>(arr: Array<A>): arr is NonEmptyArray<A>{
return arr.length > 0
}
function getArr(arr: NonEmptyArray<string>) {
return arr;
}
const arr3 = ['1']
// ^? const arr3: string[]
if (isNonEmpty(arr3)) {
getArr(arr3);
// ^? const arr3: NonEmptyArray<string>
}
Una forma simple de entender el type guard es que "transformas" un tipo a otro tipo si y sólo si cierta condición se cumple. Lo que hace que esta transformación sea segura en comparación a un simple type cast as NonEmptyArray
Revisa el playground de typescript con estos ejemplos.
✉️ Únete a Micro-bytes 🐦 Sígueme en Twitter ❤️ Apoya mi trabajo
Top comments (0)