¿Os suena este error?

¿Os suena este error?

¿Os suena este error?

Lo que JavaScript nos quiere decir es:

Otro ejemplo: ¿sabríais decir cuál es el problema aquí?
function add(x, y) { return x + y; } add("1", "2");function add(x, y) { return x + y; } add("1", "2");
Como veis, no saber de antemano de qué tipo es la variable nos supone un quebradero de cabeza.
Como veis, no saber de antemano de qué tipo es la variable nos supone un quebradero de cabeza.
Entonces, en Microsoft pensaron: sería guay tener algo que permita indicarle a JavaScript de qué tipo es una variable en cuestión, para que nos avise si estamos haciendo una operación no permitida.
Como veis, no saber de antemano de qué tipo es la variable nos supone un quebradero de cabeza.
Entonces, en Microsoft pensaron: sería guay tener algo que permita indicarle a JavaScript de qué tipo es una variable en cuestión, para que nos avise si estamos haciendo una operación no permitida.
Y así, en 2012, nació TypeScript.
Es un superset de JavaScript que añade tipado a las variables.

La idea es que usemos TypeScript mientras programamos para que el IDE nos avise si la estamos liando.
function add(x: number, y: number) { return x + y; } add("1", "2"); // <=== ojo al error que nos da el IDE!function add(x: number, y: number) { return x + y; } add("1", "2"); // <=== ojo al error que nos da el IDE!
Una vez que ya hemos acabado de programar en TypeScript, usamos su compilador para convertir el código TypeScript en código JavaScript.
Una vez que ya hemos acabado de programar en TypeScript, usamos su compilador para convertir el código TypeScript en código JavaScript.
Y si el compilador ve que hemos intentado hacer algo que no toca (como llamar a map() sobre undefined), ¡nos avisará!
Una vez que ya hemos acabado de programar en TypeScript, usamos su compilador para convertir el código TypeScript en código JavaScript.
Y si el compilador ve que hemos intentado hacer algo que no toca (como llamar a map() sobre undefined), ¡nos avisará!
O sea, que con TypeScript tenemos avisos mientras programamos y mientras compilamos el código.
Una vez que ya hemos acabado de programar en TypeScript, usamos su compilador para convertir el código TypeScript en código JavaScript.
Y si el compilador ve que hemos intentado hacer algo que no toca (como llamar a map() sobre undefined), ¡nos avisará!
O sea, que con TypeScript tenemos avisos mientras programamos y mientras compilamos el código.
Compilar (o transpilar) el código TypeScript a JavaScript es un paso necesario, ya que, recordemos, ¡los navegadores sólo entienden JavaScript!
Antes de usarlo en un proyecto real (como un servidor con Node o una aplicación con React), vamos a aprender nociones básicas de TypeScript.

En JavaScript normal, si intentamos reasignar una variable const, obviamente no nos lo permite, como en este ejemplo de abajo. Pon el ratón encima de lo subrayado en rojo para ver el mensaje de error.
¡Pero TypeScript no nos dejaría reasignarla, ni que fuera let! Prueba a cambiar el código de aquí abajo para que phone sea let, y observa el mensaje de error.
const phone = 612345678 phone = "6876543212"const phone = 612345678 phone = "6876543212"
¿Qué crees que ha pasado?
let phone = 612345678 phone = "6876543212"let phone = 612345678 phone = "6876543212"
Al cambiar a let, TypeScript ha inferido ("asumido") que phone es una variable de tipo number, así que no nos deja cambiarla por una string.
Su intención es que la variable siempre sea del mismo tipo, para evitarnos sorpresas luego.
¿Y qué hacemos si no queremos que TypeScript infiera el tipo, si no espeficarlo nosotros a mano? Lo indicamos con dos puntos después de la variable y su tipo:
let phone: number = 612345678 phone = "6876543212"let phone: number = 612345678 phone = "6876543212"
En este caso, especificar que la variable es de tipo number da los mismos resultados que no especificarlo, ya que antes TypeScript ya infería el tipo correctamente también.
Pero ahora, prueba a cambiar number por string, ¡y observa el error!
También puedes tipar los parámetros de una función, como hemos visto antes:
function add(x: number, y: number) { return x + y; } add("1", "2"); // <=== ojo al error que nos da el IDE!function add(x: number, y: number) { return x + y; } add("1", "2"); // <=== ojo al error que nos da el IDE!
¿Qué tipos básicos hay, además de number y string?
Las arrays se pueden definir de dos maneras:
const phones: number[] = [612345678, 687654321] const names: Array<string> = ["Paco", "Manuela"]const phones: number[] = [612345678, 687654321] const names: Array<string> = ["Paco", "Manuela"]
Ambas opciones funcionan exactamente igual.
Si quisiéramos una array que contiene arrays de numbers o strings, sería así:
const phones: number[][] = [ [612345678], [687654321, 931234567]] const names: Array<Array<string>> = [ ["Paco", "Obama"], ["Manuela"] ]const phones: number[][] = [ [612345678], [687654321, 931234567]] const names: Array<Array<string>> = [ ["Paco", "Obama"], ["Manuela"] ]
any sirve para especificar que la variable puede tener cualquier valor.
Observa cómo ahora no hay queja por parte de TypeScript:
let phone: any = 612345678 phone = "6876543212"let phone: any = 612345678 phone = "6876543212"
Se recomienda usar any lo mínimo mínimo imprescindible. any viene a ser como decirle a TypeScript "esta variable puede contener lo que sea", y, si estamos usando TypeScript, es justamente para evitar esto.
Cuando usamos const y asignamos una string, para TypeScript el tipo de esa variable ya no es string si no, directamente, la string asignada. Pasa el ratón encima de phone para ver qué tipo le asigna TypeScript:
const phone = "612345678"const phone = "612345678"
Como es una variable constante, TypeScript sabe que ese valor no cambiará, ergo su tipo inferido no es number si no "612345678" directamente.
Esto también pasa al asignar una variable const con una string o un booleano.
Si una variable puede tener más de un tipo, podemos unir varios de ellos usando |.
Observa cómo en el siguiente ejemplo TypeScript ya no se queja.
let phone: string | number = 612345678 phone = "6876543212"let phone: string | number = 612345678 phone = "6876543212"
Puedes generar un tipo nuevo personalizado y darle el nombre que quieras, para reusarlo luego:
type PhoneNumber = string | number let phone: PhoneNumber = 612345678 phone = "6876543212"type PhoneNumber = string | number let phone: PhoneNumber = 612345678 phone = "6876543212"
Pasa el ratón por phone en la última línea, y mira cuál es el tipo indicado.
Hay casos en los que TypeScript no puede confirmar leyendo el código si phone contendrá un número o una string.
En esos casos, no nos dejará realizar ciertas operaciones que pertenecen a uno u otro tipo. Observa el mensaje de error:
const getFirstTwoNumbers = (phone: number | string) => { return phone.slice(0, 2); }const getFirstTwoNumbers = (phone: number | string) => { return phone.slice(0, 2); }
Para que podamos hacer la operación slice() sin que TypeScript se queje, tenemos que hacerle ver que efectivamente phone es de tipo string:
const getFirstTwoNumbers = (phone: number | string) => { if (typeof phone === "string") { return phone.slice(0, 2); } return phone.toString().slice(0, 2); }const getFirstTwoNumbers = (phone: number | string) => { if (typeof phone === "string") { return phone.slice(0, 2); } return phone.toString().slice(0, 2); }
Nota: Este ejemplo es un poco absurdo, ya que bastaría con el último return porque éste ya se encarga de convertir una posible variable de tipo number a string antes de aplicarle slice().
¿Echas en falta algún tipo? Correcto, ¡los objetos JavaScript! Podemos definirlos "inline":
const user: { name: string, age: number } = { name: "Paco", age: 100 }const user: { name: string, age: number } = { name: "Paco", age: 100 }
Pero como es probable que queramos reusar estos tipos en diferentes ocasiones, podemos darles un nombre, creando así una interfaz con la keyword interface.
interface User { name: string; age: number } const user: User = { name: "Paco", age: 100 }interface User { name: string; age: number } const user: User = { name: "Paco", age: 100 }
interface User { name: string; age: number } const user: User = { name: "Paco", age: "100" }interface User { name: string; age: number } const user: User = { name: "Paco", age: "100" }
Observa el error que está pasando en la propiedad age. ¡Qué útil que TypeScript nos esté avisando del desliz!
Prueba a añadir al objeto alguna propiedad sin definirla en su tipo, y mira lo que ocurre.
Además de con la keyword interface, un objeto JavaScript también se puede definir con la keyword type:
type User = { name: string; age: number } const user: User = { name: "Paco", age: "100" }type User = { name: string; age: number } const user: User = { name: "Paco", age: "100" }
Apenas hay diferencias de funcionalidad entre usar interface o type. Elige la que más te guste :)
A lo mejor nos interesa que alguna propiedad (como age) sea opcional. Solo necesitamos añadirle un ?, y ¡listo!
const user: { name: string, age?: number } = { name: "Paco", age: 100 }const user: { name: string, age?: number } = { name: "Paco", age: 100 }
Al añadirle el interrogante, es como si la propiedad age en realidad fuera del tipo number | undefined, ya que puede ser ambas cosas (o un número, o no existir). Otro valor no será aceptado.
¡Puedes anidar interfaces una dentro de la otra, si tu objeto lo requiere!
const user: { name: string, age?: number, traits: { hair: string, height?: number } } = { name: "Paco", age: 100, traits: { hair: "brown" } }const user: { name: string, age?: number, traits: { hair: string, height?: number } } = { name: "Paco", age: 100, traits: { hair: "brown" } }
Puedes crear tipos propios combinando diferentes tipos, si así lo deseas:
interface Eggs { eggs_quantity: number; } interface Potatos { potato_variant: string; } type OmeletteRecipe = Eggs & Potatos; const recipe: OmeletteRecipe = { eggs_quantity: 25, potato_variant: "white" }interface Eggs { eggs_quantity: number; } interface Potatos { potato_variant: string; } type OmeletteRecipe = Eggs & Potatos; const recipe: OmeletteRecipe = { eggs_quantity: 25, potato_variant: "white" }
(Practica a mejorar esta tortilla extendiendo OmeletteRecipe con otro tipo llamado Onions)
Otra ventaja de TypeScript es que, como ya hemos indicado qué propiedades tienen nuestras interfaces, ¡el IDE es capaz de ofrecernos un autocompletado muy chulo!
Prueba a añadirle a recipe las propiedades que faltan, y observa como te autocompleta lo que escribes porque ya se sabe el nombre de las propiedades:
type OmeletteRecipe = { eggs_quantity: number; potato_variant: string; onions_quantity: string; }; const recipe: OmeletteRecipe = { eggs_quantity: 25, // ... sigue tú :) }type OmeletteRecipe = { eggs_quantity: number; potato_variant: string; onions_quantity: string; }; const recipe: OmeletteRecipe = { eggs_quantity: 25, // ... sigue tú :) }
Podemos crear tipos que contienen el valor literal de una string, number o boolean. Juega con las dos últimas líneas de este ejemplo:
type Roles = 'user' | 'editor' | 'admin' type HttpCodes = 200 | 400 | 500 let role: Roles; let httpCode: HttpCodes; // prueba a comenzar a escribir un posible valor // y mira lo que te indica el IDE role = 'cambiame' httpCode = 'cambiame'type Roles = 'user' | 'editor' | 'admin' type HttpCodes = 200 | 400 | 500 let role: Roles; let httpCode: HttpCodes; // prueba a comenzar a escribir un posible valor // y mira lo que te indica el IDE role = 'cambiame' httpCode = 'cambiame'
Antes hemos visto que podemos tipar los parámetros de una funcion así:
function add(x: number, y: number) { return x + y; } add("1", "2"); // <=== ojo al error que nos da el IDE!function add(x: number, y: number) { return x + y; } add("1", "2"); // <=== ojo al error que nos da el IDE!
Pero, ¿podemos tipar también el valor que devuelve una función (es decir, el return?
Efectivamente, podemos especificar lo que devuelve una función de esta forma:
function add(x: number, y: number): number { return x + y; } const result = add(1, 2);function add(x: number, y: number): number { return x + y; } const result = add(1, 2);
Si pones el ratón encima de result, verás que TypeScript nos indica que su tipo es number.
Prueba a modificar el return de la función para que devuelva algo que no sea number ("hola", por ejemplo) y mira los errores que nos muestra TypeScript.
Si la función no debe devolver nada, se puede tipar con void.
Buf, qué de cosas.
Vamos a parar aquí por hoy. En la próxima sesión, profundizaremos en más funcionalidades de TypeScript y, lo más importante, cómo usarlo en un proyecto real: en el backend con Node y en el frontend con React.
Para recapitular lo visto hoy:
Para recapitular lo visto hoy:
TypeScript es un lenguaje creado por Microsoft que añade funcionalidades extra a JavaScript. Estas funcionalidades van alrededor de tipar las variables para:
Para recapitular lo visto hoy:
TypeScript es un lenguaje creado por Microsoft que añade funcionalidades extra a JavaScript. Estas funcionalidades van alrededor de tipar las variables para:
Tenemos tipos básicos como string, number y boolean, y luego podemos tipar objetos usando interfaces. Finalmente, podemos combinar interfaces con & o crear un tipo con múltiples tipos posibles con |.
Para recapitular lo visto hoy:
TypeScript es un lenguaje creado por Microsoft que añade funcionalidades extra a JavaScript. Estas funcionalidades van alrededor de tipar las variables para:
Tenemos tipos básicos como string, number y boolean, y luego podemos tipar objetos usando interfaces. Finalmente, podemos combinar interfaces con & o crear un tipo con múltiples tipos posibles con |.
El código TypeScript debe ser compilado a JavaScript antes de que sea usado.
Recuerda que TypeScript nos ayuda mientras que estamos escribiendo el código y durante la compilación, pero no durante la ejecución del código JavaScript final.
Esto quiere decir que si a TypeScript le decimos que un valor que viene del backend es de tipo string, pero luego cuando el código se ejecuta en realidad el backend nos devuelve un number, TypeScript no será capaz de saber que el backend nos ha devuelto otra cosa, y nos dirá que no hay errores cuando en realidad los hay.
Los errores que muestra TypeScript en el IDE son un poco crípticos. Este plugin de VSCode los hace más humanos.
Los errores que muestra TypeScript en el IDE son un poco crípticos. Este plugin de VSCode los hace más humanos.
Por último, para juguetear con TypeScript y hacer pruebas, puedes crear un archivo en VSCode que acabe en .ts. O, mejor aún, usar el playground de TypeScript. Te permite escribir código en TS, ver qué errores aparecen y, además, curiosear viendo cómo luego TypeScript transformará dicho código en JavaScript.
Los errores que muestra TypeScript en el IDE son un poco crípticos. Este plugin de VSCode los hace más humanos.
Por último, para juguetear con TypeScript y hacer pruebas, puedes crear un archivo en VSCode que acabe en .ts. O, mejor aún, usar el playground de TypeScript. Te permite escribir código en TS, ver qué errores aparecen y, además, curiosear viendo cómo luego TypeScript transformará dicho código en JavaScript.
Y si quieres aprender más sobre TypeScript, el recurso oficial recomendado es su handbook.