logo

midulive


Transcribed podcasts: 605
Time transcribed: 13d 3h 7m 36s

This graph shows how many times the word ______ has been mentioned throughout the history of the program.

Amigos, hoy curso de TypeScript desde cero.
Ya hemos hecho una clase, la hicimos la semana pasada,
pero si por lo que sea te has perdido, que sepas que la hemos subido.
La hemos subido a la clase, aquí la tenemos.
¿Ves? De novato a ninja, aprende TypeScript, curso intensivo, primera parte.
Pues este curso, que te voy a dejar ahora, que te lo voy a copiar por aquí.
Espera, este soy yo, este soy yo.
Bueno, pues esa es la primera parte del curso que hicimos de TypeScript
y ahí hemos enseñado qué es la inferencia, por qué es importante aprender TypeScript.
Ahora hacemos un poco el repaso.
Si te la has perdido y lo quieres repasar tranquilamente, es una hora y cuarenta la primera parte.
Vas ahí, lo ves, lo disfrutas y ya está.
Y hoy continuamos a partir de ahí.
Vamos a hacer la revisión de dónde lo quedamos, ¿vale? Dónde lo dejamos.
Empezamos el curso de TypeScript.
Os dije, ¿por qué aprender TypeScript?
Por la popularidad, siempre, las cosas populares hay que aprenderla.
Bueno, a ver, no se trata de porque sea popular, sino que realmente hay mucha comunidad.
Cada vez se están haciendo más cosas con TypeScript y este tipo de exposición hace que vaya al segundo punto.
Segundo punto que es empleo.
Cada vez hay más empleo.
Y además, hoy, con la encuesta de Stack Overflow que ha salido y que mañana comentaremos en vivo y en directo,
pues que sepáis que los desarrolladores de TypeScript de media ganan más que los desarrolladores de JavaScript.
Si quieren ganar más dinerito, aquí tenemos las tecnologías mejor pagadas.
Pues fijaos que si buscamos aquí TypeScript, a ver si lo encuentro, TypeScript lo tenemos aquí, que de media ganan 77.100 dólares.
En cambio, la gente que es de JavaScript, de media, gana 3.000 dólares menos.
¿Que esto es indicador de algo?
Pues no es indicador de nada.
Tampoco te voy a engañar y te voy a decir, no, esto es el indicador, que no sé qué.
No, esto simplemente es una media.
Pero es verdad que obviamente TypeScript es algo valorable.
Positivamente valorable.
Lo que os digo ya, para ganar más hay que saber más.
Y aprender TypeScript es una buena idea.
Y lo tercero, que compila JavaScript.
Que al final, todo lo que sabes de JavaScript ya lo vas a poder utilizar en TypeScript.
Y que lo único que añade TypeScript son tipos, ¿vale?
Es un lenguaje de programación que es un superset de JavaScript.
Y lo único que hace es añadir tipos al lenguaje.
¿Por qué usar TypeScript?
Bueno, porque uno de los problemas que tenemos en JavaScript es que es un lenguaje con tipado dinámico y débil.
Y TypeScript viene a hacer todo lo contrario.
Lo que hace es que sea un tipo, o sea, que sea un lenguaje estático con un tipado fuerte.
O sea, que tú no puedes cambiar un string de repente a una variable que es un string, de repente asignarle un número.
O no le puedes decir, siempre tiene que tener un tipo la variable.
Que en caso de JavaScript tú no pones que una variable es un string, un número, lo que sea.
Es totalmente dinámico.
Directamente dice, ah, no, no te preocupes, que yo ya te digo lo que es esto.
Y lo hace en tiempo de ejecución.
Pero TypeScript no funciona en tiempo de ejecución.
Importante, lo hace en tiempo de compilación, de forma estática, ¿vale?
Todo el código que hacemos de TypeScript desaparece en tiempo de ejecución.
Importante.
Desaparece en tiempo de ejecución.
O sea, no llega al cliente.
Nada de TypeScript.
Así que tenlo en cuenta, porque mucha gente se equivoca y cree que lo que hacemos en TypeScript llega a los usuarios finales.
Y no llega, no llega, ¿vale?
No se hacen validaciones de tipos en el cliente.
No hace, no, no funciona.
En tiempo de ejecución no funciona.
¿Ves?
No arregla los problemas en tiempo de ejecución.
Si tenéis alguna duda de esto, ¿cómo lo podéis ver muy claramente?
Pues mira, fijaos.
En la primera clase hicimos este ejemplo.
Bueno, este ejemplo, hicimos un montón de ejemplos.
Pero veis aquí, esto de la izquierda que tenemos aquí es un montón de código de TypeScript.
Y a la derecha tendríamos el código al que lo compila.
Y como puedes ver, ves este tipo type, giro, no sé qué, no sé cuánto.
No existe.
Esto no deja de ser JavaScript puro y duro.
Y no se ve nada.
Así que ten en cuenta que lo que se ejecuta ya no tiene nada que ver con lo que hemos puesto de TypeScript.
¿Compilación o transpilación?
Bueno, ya estamos con las preguntas complicadas.
Bueno, es que a ver, transpilación en realidad no es correcto.
Todo es compilación.
Todo es compilación.
Y lo que hace TypeScript es compilar, ¿vale?
Y si no me crees a mí, porque yo que sé, no te crees, que es lo que yo digo, pues verás que si lo buscamos compilation.
Es que de hecho la configuración se llama compilation.
Mira, compiler options.
Mira, si buscas aquí en la documentación y buscas compiler, ves compiler options.
¿Y qué hacen los compiladores?
Compilar, ¿vale?
Compilando, compilando tu código.
Entonces es compilar.
De hecho, todo es compilar.
Lo que hace BabelGS, que también lo podéis ver en la propia documentación, es compilar.
¿Ves?
Compilar, compilar.
Lo que queremos decir con transpilar es que es como que estamos haciendo, llevándolo al mismo lenguaje que en el que lo hemos hecho de origen, ¿no?
O sea, compilar sería como transformarlo en bytes, como lo que hacemos en C, C++ y tal.
Y transpilar, pasar de TypeScript a JavaScript.
O de Babel a JavaScript y esto.
Pero lo cierto, lo cierto, es que la palabra correcta es compilar.
Siempre se hace compilar.
Es con compilaciones, punto.
Pero bueno, si le llamas transpilar, tampoco pasa nada, ¿eh?
Yo lo entiendo y yo no tengo ningún tipo de problema.
Hay gente que sí que se enfada si lo haces al revés, ¿no?
Si utilizas compilar.
Entonces, ¿qué necesitas para seguir el curso?
Navegador para usar el Playground, Visual Studio Code.
Y bueno, si quieres toquetear, ejecutar y tal, no TMPM.
Pero esto, nada, es opcional.
O sea, que fuera.
Con el editor de Visual Studio Code ya lo tienes.
Porque lo que comentamos es que el editor de Visual Studio Code, si no lo sabías,
está desarrollado íntegramente con TypeScript.
Todo el código, sí y si no me crees.
Porque es que la verdad, mucha gente no me cree.
Me encanta, pero no me cree.
Entonces, puedes ir al repositorio de Visual Studio Code y aquí verás que todo el código,
languages, ¿vale?
Pues aquí ves, está hecho con TypeScript.
Pero ¿sabes lo mejor de esta historia?
Que TypeScript está hecho con TypeScript también.
Que esto le vuela la cabeza a mucha gente.
Pero bueno, esto es muy típico, ¿eh?
Muchas veces los propios lenguajes de programación se hacen con sí mismos.
Es como un Inception.
Sé que es raro, pero es muy típico.
¿Veis?
TypeScript, que es este lenguaje de programación, el que vamos a aprender hoy.
Pues fijaos que está hecho con sorpresa.
Con TypeScript.
Es auto hecho.
Se hace a sí mismo.
Esto es muy normal, ¿eh?
Normalmente los lenguajes de programación, no todos, ¿vale?
Pero hay muchos que se hacen a sí mismos.
Bueno, aquí vimos algunos de los primeros ejemplos.
Y vimos algunos de los ejemplos.
Por ejemplo, aquí, pues la típica inferencia de datos.
Porque una de las cosas más interesantes de TypeScript es que a veces no tienes que escribir TypeScript.
Por ejemplo, mira, vamos a escribir aquí un playground.ts.
Y fíjate que simplemente teniendo aquí un .ts, tú cuando ya escribes aquí TypeScript, ya te funciona.
Y no tienes que hacer nada más.
Esto ya es TypeScript, que parece JavaScript.
Pero fíjate que si te pones aquí encima, ya te dice que la C va a ser un number.
O sea, estos tipos que dice el editor es porque está utilizando TypeScript por debajo.
Y vas a ver que si tú mezclas y dices esto ahora es un 1, es un string y tal, pues aquí va a decidir,
ostras, pues esto, si esto, ¿qué va a ser?
Pues esto es un string porque voy a hacer aquí la suma del string y tal.
Pero imagínate que tú le dices, bueno, esto es un number.
Vamos a decirle que esto es un number.
Pues obviamente esto no le va a gustar.
Oye, el tipo string no se puede asignar al tipo number.
Y si le dices que la C debería ser un number, pues obviamente tampoco le va a gustar.
Porque va a ser de tipo string al sumar, al concatenar un string con un número, lo que devuelve es un string.
¿Por qué?
Porque los concatena, ¿vale?
O sea, que ya podemos empezar a ver aquí dónde TypeScript nos está dando esa diferencia que no hace JavaScript.
Lo mismo incluso con los objetos, ¿no?
Ya vimos con los objetos, teníamos un objeto.
Y lo bueno de esto es que además nos hace tener autocomplete, ¿ves?
Ya detecta automáticamente las propiedades del objeto.
Y si intentas acceder a una que no existe, te va a decir, oye, que esta propiedad no existe.
No te la inventes.
Este tipo de cosas son las buenas de TypeScript.
Tenemos los tipos básicos.
Ya hemos visto la inferencia de datos.
Es que TypeScript automáticamente es capaz de detectar los tipos de nuestros datos.
¿Vale?
Y más aquí, los tipos especiales any, que lo volveremos a ver hoy.
Que es un tipo que es como ignorar los tipos.
Cosa que jamás hay que hacerlo.
Esto es como una mala práctica.
Y a veces se hace por necesidad o para arreglarlo más adelante.
Pero no para dejarlo por siempre porque si no, lo que hacemos es ignorar los tipos.
¿Vale?
Vimos funciones, que esto lo repasaremos hoy también.
Cómo tipar a row functions, funciones que no devuelven nada.
¿Cuál es el tipo que tenemos que poner?
Que es void.
También vimos never, que esto lo volveremos a ver hoy para que veáis qué significa never.
Never básicamente es un tipo que se refiere a cuando nunca, nunca va a ocurrir.
Es un tipo de datos que nunca va a existir.
¿Por qué?
Pues que imagínate un código que hace un retón antes de que pueda devolver algo.
Bueno, pues eso significaría que su tipo de dato es never.
Porque nunca va a ocurrir.
Eso lo repasaremos hoy también.
¿Vale?
Es un tipo imposible.
Muy bien.
F18.
Me ha gustado eso.
Un tipo imposible.
¿Qué más tenemos por aquí?
Bueno, hemos visto las funciones anónimas.
Inferencia de datos que no siempre funcionan los parámetros.
Las funciones, por ejemplo, si nosotros ponemos esto, esta función que tenemos aquí.
Aquí, fíjate que si me pongo encima, me dice el parámetro a tiene un tipo any.
Y es porque TypeScript tiene limitaciones.
O sea, TypeScript es muy listo muchas veces porque es capaz de inferir, o sea, de detectar cuál va a ser el tipo de una variable, pero a veces tiene limitaciones.
Como yo, que a las 8 de la mañana estoy limitado mentalmente, pues exactamente lo mismo.
Bueno, aquí tenemos suma.
Pues a dice, vale, aquí tengo el parámetro a, pero no sé cuál es el tipo de a.
Y por lo tanto, a más b, claro, si intentas aquí a, te dice que es any.
Y b es any.
Y esto está mal.
Así que tendríamos que decirle que esto sería un number, por ejemplo, y que esto es un number.
Nosotros le tenemos que indicar cuál es el tipo porque no es capaz de inferirlo.
Y si hacemos esto, ya nos dice, oye, no puedes utilizar strings, que me has dicho que son números, ¿vale?
Muy bien.
Objetos, ¿vale?
Los objetos súper interesantes.
Cómo crear funciones que devuelvan objetos.
Cómo hacer propiedades que sean opcionales.
Y hoy vamos a ver un tema muy interesante que son la diferencia entre tipos e interfaces, ¿vale?
Que en la primera clase, la semana pasada, me lo estuvierais preguntando como 80 millones de veces.
Bueno, pues hoy vamos a ver las interfaces y os voy a explicar cuál es la diferencia y cuál es la que deberíais usar, según mi opinión.
Según mi opinión, ¿vale?
¿Qué más cositas vimos?
Bueno, vimos que podíais utilizar RedOnly para evitar que se pudiese modificar una propiedad.
Esto es súper interesante, muy poco utilizado, de forma sorprendente.
Pero imaginad que tenemos aquí ID, un nombre, vamos a poner Spidey o Miles.
Vamos a poner que es Miles Morales.
Que no sé, debe tener 21 ya.
Y Sati, vamos a poner que sí, hombre.
Que sí que es Sati.
Así que lo ponemos en True.
Y una cosa que está muy chula es que imagínate que la ID, la ID de este objeto, queremos que no sea modificable.
Claro, si tú haces así, giro.id22, ¿vale?
Si le quitamos esto, pues puedes hacer esto.
Pero la ID de un héroe no debería ser modificable porque no queremos que nadie la toque.
Así que lo que podemos utilizar es la propiedad de esta, ReadOnly.
Y así nos da un error cuando alguien intente modificar esta propiedad del objeto, ¿ves?
Es una forma de, no lo hace inmutable, cuidado, no lo hace inmutable, sino que no te permite cambiarlo.
Pero el valor sigue siendo mutable.
Lo que pasa es que te da un error cuando lo intentas, ¿vale?
Son cosas diferentes.
Son dos cosas diferentes.
La creación de la ID nosotros la hicimos aquí dentro.
Y con esto hicimos una cosa muy chula.
Mira, con este código, te voy a enseñar esto porque creo que esto es una de las cosas que más explotó la cabeza a la gente, que está muy chulo, ¿vale?
Mira, hice esto, ¿no?
Fijaos que aquí en el type giro puse que la ID era opcional, que ya no es opcional.
Vamos a poner que es obligatoria.
Y que, ah, bueno, voy a poner que es opcional porque esto todavía pone giro.
Y le dijimos que era number.
Y esto había que cambiarle un string, ¿vale?
Lo cambiamos a un string.
Pero expliqué que son los union types, los template union types, que es muy chulo.
No sé si conoces, aquí en este código estamos creando aquí una ID utilizando esto.
Esto es una cosa que es de la plataforma web, ¿vale?
Es una cosa de la plataforma web.
Esto lo tienes en el navegador.
De hecho, para que veas, si nos vamos aquí y abro las herramientas de desarrollo y me voy aquí a la consola,
si pegamos esto, ¿ves?
El Crypto Random UID, esto te devuelve una ID aleatoria.
Entonces, el tema es que esto te devuelve un identificador único siguiendo un algoritmo concreto.
Y esto es algo de la plataforma web.
Si estás intentando soportar Internet Explorer 11, puede ser que no lo soporte,
pero debe tener un soporte bastante amplio, ¿eh?
91%.
¿Ves?
Internet Explorer 11 no lo soporta.
Entonces, bueno, si necesitas Internet Explorer 11, pues a lo mejor necesitas un polyfill o una biblioteca aparte, ¿vale?
Pero si no, pues ya sabes que lo tienes.
Dicho esto, ¿qué pasa con el Random UID?
Pues que si te fijas, la ID que crea es string, guión, string, guión, string, guión, string.
Y explicamos qué son los template union types,
que son unos tipos muy chulos que te permite decirle la forma que va a tener el string.
¿Ves?
Tú aquí le podías decir, oye, mira, esto en realidad va a ser string y aquí va a tener string, string, string.
Y le podías decir que esta era la forma.
Así que si tú intentabas poner un string normal, un, dos, tres, ¿ves?
Te dice, no, porque el string que tú estás intentando no se puede asignar a esta forma del string que tiene guiones.
Y esto se llama template union types.
Es una de las cosas más potentes y es bastante sencillo, pero es muy potente que tenemos en TypeScript.
El hecho de decirle, oye, ¿cómo son nuestros strings?
Pues mira, tienen guiones.
Buah, pues es alucinante, ¿vale?
Es alucinante.
Y aquí nos obliga a asegurarnos que le ponemos el tipo de string correcto.
No un string en general, sino correcto.
Otro ejemplo muy básico para que lo entendáis, ¿vale?
Para imaginar que tenéis hexadecimal color.
¿Cómo son los colores hexadecimales?
Pues normalmente así, con un hash o como le queráis llamar, o con una almohadilla.
No sé cómo le llamáis, pero depende.
Con un gato, no me acuerdo los nombres que tienen en Sudamérica, Latinoamérica.
No me acuerdo cuáles son, ¿no?
Pero una cosa que tenemos por aquí es que le podríamos decir, claro, ahora dice hexadecimal,
pues podríamos decir que es un string, almohadilla.
Yo le llamo almohadilla.
Es verdad, numeral le llamáis en muchos sitios.
Mucha gente hace esto.
Pero una cosa que es muy interesante es que, claro, si vosotros hacéis esto, si le decís,
oye, tengo un tipo que es el color, que es string, ¿vale?
Y le decís que esto es el color.
El problema es que podéis ir a otro sitio, a otro color, ¿no?
Black hexadecimal.
Y os podéis equivocar y hacer esto.
Que esto pasa mucho, ¿no?
Olvidaros el numeral, la almohadilla, el hashtag, como le queráis llamar, ¿no?
Entonces, ¿qué es lo que pasa?
Que en lugar de hacer esto, lo que podéis hacer es decir, no,
voy a usar un template union type de forma que me aseguro que siempre tenga la almohadilla,
el numeral, delante.
Y así encontraré los errores como este.
Está súper chulo esto.
Es una cosa que veo que mucha gente no usa.
No sé si es porque no se explica mucho los tutoriales, pero bueno, ya lo sabéis.
Vimos cómo tener union types, intersection types.
Vimos también el type indexing, que básicamente es extraer un tipo.
Bueno, ¿qué más vimos?
Vimos algunos, ya vimos los arrays, muy interesante, ¿no?
Bueno, que no podemos hacer esto con los arrays en typesing, ¿vale?
¿Por qué?
Porque si tú creas un array y no le indicas el tipo, fíjate que te dice,
oye, si intentas hacer un push y me metes cualquier cosa, no, no, o sea, no me lo voy a comer.
Y se va a quejar.
¿Por qué?
Porque en languages que hemos creado, fíjate que me dice que es un array de nevers.
¿Por qué?
Porque, claro, como no le hemos dicho qué hay aquí dentro, él se cree que es un array vacío lo que quieres hacer.
Así que al tiparlo, tenemos que decirle, bueno, pues queremos que sea string, ¿vale?
Un array de strings.
Y ahora sí que nos permitirá añadir strings, ¿vale?
Y un array de strings puede ser un array vacío y un array de strings.
Así que importante esto.
¿Qué más?
¿Qué más tenemos aquí?
Vale, el tema de los arrays, esta sería la otra sintaxis para crear arrays,
que también podríamos utilizarlo con nuestros tipos.
Y finalmente vimos las tuplas.
Las tuplas es una forma muy interesante de hacer arrays que son fijos en tamaño.
¿Cómo sería un array de arrays?
Pues eso también lo vimos, justamente, mira.
Y vimos un game board.
Imagínate el 3 en raya, ¿no?
3 en raya.
El 3 en raya sería un array de arrays, ¿no?
Porque sería un array, o sea, el board sería un array donde tendríamos cada una de las 3 posiciones.
Que aquí en realidad podríamos tener la X, aquí podríamos tener otra X, ¿no?
Es como estaría la gente jugando, sería algo así.
Sería un array de arrays.
Pues lo que puedes hacer simplemente es decir, oye, aquí vamos a tener, podemos tener un string de arrays.
Se va a quejar porque tenemos que son nuls, por lo tanto no se podría.
Podríamos ponerlo, ah, no, así no.
Tendríamos que hacer o string o null, ¿vale?
Y ya lo tendríamos.
No se puede asesinar al tipo string.
Vale, pues no.
No le gusta.
No le gusta, porque no le gusta.
Nunca lo he hecho...
A ver, que en lugar de los nuls lo podríamos hacer así, ¿eh?
Que también tiene más sentido.
String, esto por aquí, esto por acá, pam.
Vale, que he hecho mal.
Ah, ¿por qué?
¿Qué te he dicho?
No, es que se hace así, claro.
Se hace asá.
Se hace así, ¿vale?
Se hace...
O sea, estaba bien lo que había hecho.
Estaba bien.
Lo que pasa es que se me había olvidado el array de arrays.
Para hacer array de arrays es un array de un array de strings.
Y aquí tendríamos un array de un array de strings.
Fíjate que hemos puesto dos arrays, ¿vale?
Y este array sería el array de arrays.
Así es como sería.
Esto sería una matriz, ¿vale?
Un array de arrays es una matriz.
Y esto sería una matriz de 3x3.
Y para hacerlo sería así.
Pero lo que explicamos la otra vez es que esto tiene problemas, ¿vale?
Esto está...
No está mal, ¿vale?
Y si es un número, pues nada.
Cambias el string por number y ya está.
Ahora, ¿qué pasa?
Que esto estaría...
O sea, está bien, pero también estaría regulinchis.
¿Por qué?
Sí, también lo podéis hacer con esta sintaxis, ¿vale?
Si os preferís, podéis hacer esta sintaxis.
Esto sería un array de strings.
Y a Leo B lo mismo.
Podrías hacer un array de strings, ¿vale?
Esta sería la otra sintaxis.
A mí me gusta más la otra, pero podéis utilizar la que queráis, ¿vale?
Entonces, esto tiene un problema.
Y el problema es que esto es un array de arrays,
pero si yo añado aquí otro, esto se lo va a comer con patatas.
Porque fíjate que no le hemos dicho que esto tenga que ser un 3x3.
Y podemos modificar y hacer cualquier cosa, ¿no?
Así que lo que tenemos que hacer es utilizar las tuplas.
Mira, las tuplas podemos decirle, para que básicamente entendamos bien la cosa.
Vamos a copiar este ejemplo, ¿vale?
Y haremos la tupla.
En este ejemplo tenemos el tipo de cell value, que puede ser el string x,
el string vacío o o, ¿no?
Y aquí le decimos que tenemos un array de arrays de strings que pueden ser uno de estos tres.
Y queda tal que así.
Pero aquí tenemos el mismo problema.
Para esto necesitamos crear, usar una tupla, que la tenemos justamente aquí.
Y una tupla es simplemente decirle el tamaño fijo que va a tener nuestro array.
Así que lo que podemos hacer aquí es crear nuestro array y decirle qué es lo que va a tener dentro de cada uno.
O sea, tendríamos aquí el array y decirle, vale, tenemos el cell value, cell value, cell value, cell value, cell value, cell value.
Ya está.
Lo que estamos es indicando perfectamente qué es lo que esperamos.
¿Por qué?
Es un array donde tiene tres posiciones en cada uno de los elementos.
O sea, tiene tres filas y tres columnas.
Y fíjate que si tú ahora intentas añadir otra cosa, pues ahora sí que se queja.
Estos serían las tuplas.
Arrays fijos de longitud.
Si no lo has entendido, no pasa nada.
Tenemos el ejemplo más típico, por ejemplo, RGB.
¿Qué RGB?
Podríamos decir el tipo RGB.
RGB.
Sería una tupla de tres números.
RGB es red, green y blue.
Que básicamente son los colores, ¿no?
Cuando queréis tener el color, el black, sería 0, 0, 0, ¿no?
Y luego tendríamos el white, que es 255, 255, 255.
Esto va súper bien aquí.
Porque podéis decir que son RGBs y ya está.
Y esto tiene un tamaño fijo.
Si intentáis poner uno más, se va a quejar.
Y lo mismo podéis pensar con las coordenadas, ¿no?
Coordinadas y coordinates.
Que tenéis latitud y longitud, por ejemplo.
Pues esto sería un point.
Tendrías aquí 3, 14 por 71.
Bueno, y si intentáis poner otra cosa, se debería quejar cuando decís que esto son las coordenadas.
Estos son las tuplas, ¿vale?
Sí, he escrito mal coordinates, pero lo habéis entendido, ¿eh?
Es coordinates con la i.
Y ahí es donde nos quedamos.
Y con las tuplas vamos a seguir.
Porque las tuplas, ¿vale?
Las tuplas tienen un problema.
Vale, fijaos.
Imaginaos el tema de las tuplas.
Vamos a pensar que tenemos aquí el tema del RGB y todo esto.
Esto tiene un problema.
¿Y cuál es el problema que tienen las tuplas?
Bueno, el problema que tienen las tuplas es que son mutables.
Son modificables.
O sea, que podríais ir aquí al black y hacer un push de 4 y se lo come con patatas esto.
Con patatas fritas se lo come.
Con patatas fritas.
Y esto es un problema, obviamente, ¿no?
Porque esto hace que ahora black en realidad tenga 4 en lugar de 3.
Y hemos dicho en la tupla que debería tener 3.
Así que estamos rompiendo directamente el contrato que debería tener.
Esto es un...
Yo creo que es un fallo de TypeScript.
De hecho, hay una isu abierta desde hace 10.000 millones de años.
¿Ves?
Remove destructive methods in tupletype.
Esto es del 2016 y todavía no lo han arreglado.
Y fijaos que aquí, pues, estaban hablando, lo han cerrado, no sé qué.
Y parece que todavía no ha habido mucha respuesta.
¿Y por qué es esto?
Bueno, porque si lo hacen, estarían rompiendo la retrocompatibilidad.
¿Vale?
Toda la compatibilidad hacia atrás y no quieren hacerlo.
Hay una forma fácil de arreglar esto en la que podéis utilizar justamente lo que dijimos
en la anterior clase, que es el modificador Red Only.
Si hacéis Red Only el RGB, una vez que lo creáis, que son solo 3, ya no podréis hacer
ni push, ni splice, ni nada.
Sino que simplemente yo os recomiendo que si las tuplas queréis que sean totalmente fijas
y no evitar esto, o sea, y evitar esto, pues le metéis el Red Only y ya lo tenéis solucionado.
Esta sería una forma de arreglarlo.
Así que mira, esto que creo que lo habíamos dejado pushando.
Ah, mira, lo tenemos aquí el ejemplo.
Vale.
Pushando en las tuplas, pues ya sabéis cuál sería la solución que yo os comentaría.
Ahora vamos a hablar de los enums, de las enumeraciones, ¿no?
De esto hablé de algo parecido en un vídeo hace poquito en mi canal de YouTube sobre no usar strings en tu JavaScript para esto.
Y aquí mucha gente, con razón seguramente, pero fuera de contexto también, empezó a comentar que lo mejor era utilizar enums, ¿no?
¿Por qué? Porque, no, con enums se soluciona y tal.
Y tienen razón.
Pero, pero en JavaScript no existen los enums, solo existen en TypeScript.
Mirad, fijaos en este ejemplo, ¿no?
Tenemos una función imprimir mensaje.
Vamos a hacerlo.
Vamos a hacer este ejemplo.
Normalmente, imagina que esto es JavaScript.
Vamos a poner aquí que esto es JavaScript.
Tenemos una función mostrar mensaje y aquí tenemos el tipo de error.
Tipo de error.
Dependiendo del tipo de error, imagínate que tenemos aquí, yo que sé,
y el tipo de error es not found, pues entonces hacemos un console.log, no se encuentra el recurso, ¿vale?
Si el tipo de error es lo que sea, tipo de error, ¿vale?
Aquí tenemos como diferentes errores.
Esto está mal, ¿vale?
Está mal por diferentes motivos, que es bastante importante que lo sepas, ¿no?
En este tanto, lo mejor es utilizar lo que se...
Estos son Magic Strings.
¿Por qué?
Porque has puesto una cadena de texto a mano.
Imagínate que te equivocas y haces esto.
O que en otro sitio lo quieres utilizar y de nuevo tienes que acordarte de esto, ¿no?
En JavaScript es crear, pues a lo mejor, una constante donde te evites esto, ¿no?
Tienes la constante que tienes error types, ¿vale?
Y entonces aquí dices, vale, tengo el error not found, y el not found, pues es not found,
y aquí cada uno lo haríamos así.
Y ahora, en lugar de utilizar directamente el string, pues nada, pondríamos error types.notfound.
Y esto ya empieza a mejorar bastante.
Además de la elegibilidad, también tenemos la posibilidad de exportar esta constante
y utilizarla en otro punto de nuestra aplicación, ¿vale?
O sea, que podríamos reutilizarlo en otro punto de nuestra aplicación.
Así que, forbidden y tal.
Esto sería JavaScript, pero en TypeScript tenemos la posibilidad de utilizar una cosa
que se llaman enums, enumeraciones, ¿vale?
Y en las enumeraciones puedes pensar en un montón de cosas.
Como por ejemplo, mira, en JavaScript podríamos hacer algo así, ¿vale?
Ahora, en TypeScript lo mejor sería que usásemos enums.
Y es súper importante lo que te voy a explicar, ¿vale?
Porque los enums tienen diferentes historias.
Tienen diferentes historias.
Y es que los enums, depende cómo los hagas, pueden compilarse a código JavaScript o no.
Eso lo vamos a ver ahora.
¿Cómo funcionarían los enums?
Bueno, lo único que tendríamos que decir es, vale, ¿cuáles son los que queremos enumerar?
Pues es muy parecido a lo que hemos hecho aquí, ¿vale?
Lo vamos a copiar, solo que vamos a poner enum, quitamos esto y ahora esto lo podemos eliminar.
Ni siquiera lo necesitamos, ¿vale?
No necesitamos por ahora esto.
Luego veremos qué se puede hacer también.
Y el código sería muy similar en TypeScript.
Sería muy, muy similar.
Error types, punto not found y esto funcionaría correctamente.
Si vamos aquí a nuestro playground, ¿vale?
Entonces, ¿ves?
Esto funciona bien.
Error types y cuando hagas punto, vais a ver que además deberíais tener el, no sé por qué a veces no, ¿ves?
Tenéis el autocomplete.
Lo está detectando automáticamente.
Aquí tenemos las enumeraciones.
¿Para qué podéis utilizar las enumeraciones?
Pues, por ejemplo, para los días de la semana.
Para una colección de datos finita, ¿vale?
Colección de datos finita, no infinita.
¿Por qué?
Porque si utilizáis, si intentáis que sea infinita, ¿vale?
Si intentáis que sea infinita, no podéis utilizar enums.
Tiene que ser datos finitos.
Que sean 5, 10, 15, quizá 20, pero no pueden ser 280, ¿vale?
Tienen que ser datos que puedas controlar.
Que son finitos, que ya los conozcas y que puedas tratar sobre ellos.
No pueden ser dinámicos, no te los puedes ir inventando, ¿vale?
Así que tienen que ser finitos.
Los días de la semana, los meses del año, por ejemplo.
Los tipos de error que vamos a tener.
Los tipos de viviendas de una aplicación que sea de vender pisos, por ejemplo.
Yo que sé, cosas así.
Así que esta sería la forma, ¿no?
De tener los enums.
Pero te voy a explicar algo que esto es lo típico que muchas veces no se explica, especialmente en muchos cursos.
Que es cómo compila esto, ¿no?
¿Cuál es la transformación que hace esto, no?
Vale.
Pues fíjate.
Mira esto que si...
Bueno, aquí el tipo de error.
No he puesto tipo de error, no he puesto nada, pero esto debería ser un tipo de error types.
El enum lo podéis utilizar aquí como un tipo, ¿no?
Y fíjate que se me estaba quejando.
Aquí en los errores me pone uno.
Porque si no, tipo de error era any.
Y para arreglarlo decimos tipo de error es del enum error types.
O sea, va a ser uno de los tipos de error que tenemos, ¿vale?
Entonces, fíjate que al hacer el enum, todo el código que está generando aquí.
Esto es JavaScript.
¿Qué es lo que hace?
Y esto es súper interesante para entender correctamente los enums.
Lo que hace por defecto es que aquí a cada uno le está poniendo un índice.
Esto es cero.
Esto es uno.
Y esto es dos.
¿Ves?
Le está dando como un valor.
Dice, el not found, su valor es cero.
Un authorized, su valor es uno.
Forbidden, su valor es dos.
Entonces, lo que está haciendo es, aquí sí está compilando un código.
¿Qué pasa?
Que esto a veces puede ser problemático.
Porque a lo mejor no quieres generar ese código de más.
Para solucionar esto, una cosa que puedes hacer es decirle, oye, estos enums, yo en realidad
ya sé que estos enums no quiero que, no sé, que me los transpiles.
Porque ya sé cómo funcionan.
Pues puedes decir que son una constante.
¿Y qué es lo que va a hacer esto?
Te va a quitar todo el código que había generado.
Fíjate la diferencia, que esto muchas veces parece tontería, pero hay gente que se pone
así.
Vale, pues la constante, fíjate que lo que hace es cambiar los valores en línea y donde
tenía aquí esta asignación del error types not found, lo que dice es, vale, este yo sé
que es el cero y por lo tanto lo cambio en un cero.
Y te deja un comentario aquí para que sepas de dónde lo has sacado.
Esto obviamente luego si lo compilas, o sea, si lo vas a llevar a producción, esto
desaparece. Pero para que sepas, ¿no? Para si quieres verlo, podrías ver aquí esta
referencia. Y lo mismo con el 1 y con el 2. O sea, fíjate la diferencia entre uno y
otro. Bueno, entonces, ¿cuál debería utilizar? ¿Debería utilizar siempre const? ¿Debería
utilizar siempre sin const? Luego te lo comento.
Porque también otro tema muy común es que hay veces que, claro, a lo mejor no te va
bien que empiece por el cero. O sea, a lo mejor no te va bien que el cero sea la idea
del not found. A lo mejor ya tienes una idea por ahí. Bueno, imagínate que quitamos esto.
Ya habéis visto que al principio empieza por el cero y le pone números. Pues otra cosa que
podéis hacer aquí, en realidad, es ponerle lo que os dé la gana. ¿Vale? Podéis poner aquí,
yo qué sé, not found. Podéis ponerle un string. Y aquí ya vais a ir viendo, pues, not found.
Aquí le podéis poner un authorize. Y esto puede ser bastante interesante,
especialmente si tenéis una base de datos en la que ya tenéis diferentes claves
para esto. Imagínate que una base de datos ya tienes los errores de los tipos
de error y lo que quieres es utilizar exactamente esa cadena de texto. Pues lo
tendrías que hacer así. Y lo mismo, si utilizas el const, lo que va a pasar es
que directamente lo cambia. ¿Vale? Así que ahora ya sabéis cómo utilizar en UMS y
además cómo podéis hacer de indicarle exactamente el tipo. Ahora, ¿por qué no
deberías usar el const? ¿No? Porque si miras esto, dices, joder, es bastante
evidente que siempre voy a querer utilizar el const en el enum porque genera
menos código. O sea, va a ser mejor y tenemos menos código. O sea, ¿cuál sería
la razón en realidad de añadirle el const? No le veo ningún tipo de sentido,
¿verdad? Hay una explicación. La explicación... A ver, os voy a poner la
explicación oficial y mi explicación. La explicación oficial la podéis encontrar
aquí escondida por Daniel Rosenhauer, joder, Rosenwasser, Daniel Rosenwasser, joder, qué
complicado, ¿no? Del 2018, donde aquí pues hablaba, ¿no? Const enum a veces se malinterpretan,
se utilizan mal porque pueden ser bastante buenas internamente, no sé qué, no sé cuánto,
bla, bla, bla, bla. Esta es la oficial. Yo os voy a intentar comentar cuándo deberías
utilizar una y otra, en mi opinión. Si alguien no está de acuerdo, lo puede decir en el
chat. Total, yo os diría que siempre que podáis, utilizáis la const. Siempre que
podáis utilizar, utilizáis esta para no generar código de más. Pero tenéis que
utilizar esta, de enum, cuando estáis creando una biblioteca, una librería o una parte,
un componente que va hacia el exterior, ¿vale? Que está fuera de tu aplicación. O sea, que
quieres que se consuma fuera de tu aplicación. ¿Por qué? Porque va a ser mucho más fácil
que esto al final se genere como un objeto en el que alguien lo pueda consumir desde
fuera y a lo mejor le interesa. Por ejemplo, si tienes JavaScript, le va a interesar que
esto sea algo que pueda importar, que pueda utilizar, que a lo mejor pueda mirarle los
tipos, lo que sea. Así que es súper importante esto, ¿vale? Entre el const, entre la forma
de const, que genera menos código, y esta de aquí, ¿vale? Depende más bien de lo que
vayas a hacer con ese código. Normalmente siempre el const. Pero si por lo que sea este
num es algo que van a consumir hacia afuera, pues entonces sin const, ¿vale? Muy bien.
Aparte, vamos ahora con las aserciones de tipos. ¿Qué son las aserciones de tipos? Esto
es un concepto muy importante en TypeScript. Lo vais a necesitar muchas veces y os va
a dar una bofetada en la cara un montón de veces. Mira, el ejemplo más típico de una
aserción de tipos es cuando, por ejemplo, estamos aquí en... Mira, voy a copiar esto. Voy a copiar
este ejemplo que habíamos hecho. Ah, ya lo tengo aquí. Vale. Imaginad que vosotros estáis
trabajando con HTML y queréis dibujar en un canvas. Lo que sea. En un canvas. Imagínate
el típico ejemplo. Tenéis un canvas. No sé si sabéis que hay un elemento canvas en el que
podéis dibujar, ¿vale? Y queréis recuperar el elemento, getElementById y le decís, vale,
recupérame el canvas. Esto también lo podríais hacer con el botón. Imagínate, con el botón.
Mira, imagínate un botón que quiere recuperar el botón. Vale. ¿Qué pasa con este botón,
no? O sea, los botones tienen ciertos atributos que a lo mejor no tiene un div. Si intentas
pillar un div, un canvas, un input o un párrafo, los atributos, propiedades, métodos que tendrán
serán diferentes. ¿Y qué pasa? Imagínate el canvas. Que si ponemos aquí canvas, canvas. ¿Cómo
sabe? ¿Cómo sabe TypeScript que realmente estás recuperando un elemento canvas? ¿Cómo
lo sabe? Pues no lo puede saber. Es imposible. TypeScript no es capaz, a partir de aquí, saber
que realmente quiere recuperar un elemento canvas. No lo sabe porque TypeScript no funciona
en tiempo de ejecución, ¿vale? Por eso lo decía. Tiempo de ejecución, tiempo de ejecución.
Porque es imposible saberlo. Así que lo que necesitamos es nosotros indicarle realmente
de qué trata. ¿Por qué? Porque como TypeScript no lo sabe, si tú le dices, vale, pues voy
a recuperar el contexto del canvas, getContext2D, ¿no? Y me dice, oye, es que canvas posiblemente
es nul. Vale, pues es nul. Perfecto. Lo arreglamos con esto, ¿no? Para saber si es nul, o mejor,
si no lo queréis arreglar así, dice, vale, si tengo canvas, ¿vale? Si canvas, si tengo canvas
y es diferente a nul, entonces ejecuto esto. Pero fíjate que todavía se queja. Y dice, oye,
la propiedad getContext no existe en el tipo HTML element. ¿Qué es lo que está pasando
aquí? Lo que está pasando aquí es que el document.getElementById nos puede devolver dos
cosas. Nos puede devolver nul si no lo encuentra. Y de forma general, lo que nos puede devolver
es un HTML element. Porque no sabe exactamente cuál es el elemento que va a encontrar. Si es
un input, un botón, si es un span, no lo sabe. No es capaz de adelantarse. Así que nos pone
un tipo general, que es HTML element. Digamos que nos pone el tipo más general. Y nosotros
en realidad necesitamos un tipo más específico, que es el canvas element, ¿vale? Este es el
que necesitamos nosotros, que es más específico. El problema es que se lo tenemos que decir
de alguna forma que normalmente, pues, no nos gusta. ¿Por qué? Porque tendríamos nosotros
que indicarle realmente que esto es un HTML canvas. Por eso lo que se hace es esto de
as HTML canvas element. Esto lo que hace es que nosotros le estamos obligando, le estamos diciendo,
oye, tienes que tratar esto como un HTML canvas element. Lo malo, lo malo de hacerlo en este punto
es que, claro, ahora al canvas le estamos como nosotros obligando. Le estamos diciendo a TypeScript
básicamente que se fíe de nosotros. Lo cual, no sé, entre tú y yo, pero no somos muy de fiar
muchas veces. Así que lo que está pasando aquí es que estamos diciendo, oye, esto es un HTML canvas,
pero fíjate que ahora hemos perdido totalmente el hecho de indicarle que esto podía ser nul.
Hemos perdido esa validación. Así que hay que tener un poco de cuidado cuando utilizamos
las aserciones de tipos. Cosas que podéis intentar. Si ponéis esto aquí, ¿vale? Se queja.
¿Por qué? Porque lo que tenemos aquí a la derecha no encaja con esto que tenemos aquí,
porque canvas puede ser nul. O sea, que cuidado con esto. Algo que normalmente tiene mejor pinta
es que la aserción lo hagáis después de la comprobación, ¿no? De forma que este canvas
lo hagáis aquí, ¿no? Aquí. Y aquí le puedes decir, oye, el canvas trátalo como un HTML canvas element.
Pero de nuevo, si miramos este código, tened cuidado con una cosa. Y este código, fijaos,
que aquí, este HTML canvas element, aquí desaparece. ¿Qué pasaría? Imagínate que te equivocas
y aquí devuelve un span. Que la hemos liado parda otra vez. La hemos liado porque aquí
TypeScript no se da cuenta. ¿Veis que no se está dando cuenta? No sabe que realmente va a recuperar
un span. Así que normalmente otra cosa que podéis hacer es intentar mirar que canvas sea una instancia
del HTML canvas element. Y de hecho, cuando hagáis esto, ahora vamos a explicar este concepto,
pero una vez que hacéis esto, vais a ver que además TypeScript lo detecta y dice,
ostras, con la comprobación que has hecho aquí de ver que es diferente a nul y que me dices que canvas
sea una instancia de HTML canvas element, ahora sé que canvas es un HTML canvas element
y que puedes acceder al getContext. Y esto es JavaScript. Estamos haciendo JavaScript,
pero utilizando nuestro JavaScript, lo que está haciendo TypeScript es darse cuenta
que lo que tiene aquí es un canvas element. Y esto es muy interesante y a veces lo hacemos
regulinchis, ¿vale? Fíjate, como lo que tenemos a la izquierda es justo lo mismo
que compila el JavaScript. Pero esto que está haciendo aquí es inferencia.
TypeScript se da cuenta que dentro del if ya solo va el canvas, va a poder ser un HTML canvas element, ¿vale?
Así que, y esto obviamente ya lo podéis llegar a poner así y ya lo podéis hacer así.
Lo digo porque hay veces que este tipo de cosas la gente como no termina de entenderlo
y se pone como loca a utilizar las aserciones estas como as, HTML, canvas element y cosas así, ¿vale?
Pero hay veces que lo mejor es ser correcto tanto en los tipos, tanto en los tipos.
Dice, pero dice span, pero no importa porque nuestro código no va a petar.
Este código ahora no va a petar. Y está bien. Fíjate que aunque aquí dice span y va a recuperar un span,
como va a entrar y va a hacer este check, como va a hacer este check,
este check no va a entrar en este código. Aquí no entra. ¿Por qué?
Porque este canvas es un span, como tú dices, y ya está.
Pero con el otro código que teníamos antes sí que petaría.
Mira, este tipo de cosas son un poco las que marcan la diferencia entre saber TypeScript
y no saber TypeScript, ¿vale? ¿Por qué?
Porque muchas veces la gente se cree que TypeScript es mágico.
Mira, esta es buena.ts, ¿vale?
Esta sería la buena. Y la mala, esta es la buena, la que hemos hecho antes.
No sé por qué me dice que no puedo volver a declarar canvas, pero bueno.
Vamos a ponerle C.
Esta sería como la buena.
Y esta sería la falsa, la que la gente no pasa nada.
Esta sería la peor, ¿no? HTML canvas element.
Esta sería la peor porque nos quitaría el soporte este y esto podría petar si no lo encuentra.
O sea, esto en runtime petaría. Petaría si no lo encuentra.
Si no encuentra el HTML canvas, petaría.
Luego tendríamos esta que sería un poco mejor, sería mejor, ¿no?
Esta sería mejor, pero todavía podría petar. ¿Por qué?
Porque si tú pones esto de span, fíjate que TypeScript no te está dando ningún tipo de error, ¿vale?
Esto no te está dando ningún tipo de error, pero esto petaría porque el JavaScript que ejecuta,
lo podemos ver aquí, ¿ves?
No está haciendo ningún tipo de comprobación sobre canvas.
Y como aquí hemos dicho que es un span y canvas no es un span, esto petaría.
Y esto lo podéis ver muy claro, ¿eh?
Para que veáis que esto peta, porque a lo mejor no lo creéis.
Fijaos, entramos aquí, vamos a Codilink.
Si nos vamos y pegamos aquí este JavaScript y aquí yo pongo canvas, ¿vale?
Si miramos aquí en la consola, vais a ver que esto, vale, ahora no me peta porque, ah, porque me dice que sea diferente a null.
Vale, span, vale, span, span, vale, ahora sí.
Vale, no sé por qué, ah, GetElementById, he puesto GetElementById.
QuerySelector, ¿vale?
Es que como pone diferente a null, lo tiene que recuperar.
¿Ves?
Canvas.getContext is not a function.
O sea, os petaría por mucho TypeScript que utilicéis.
La correcta, la correcta que une los dos mundos sería decir, oye, en lugar de utilizar la aserción de tipos,
vamos a mirar que canvas sea una instancia de HTML Canvas Element.
Y la pregunta del millón es, ¿por qué esto funciona en TypeScript y por qué funciona en JavaScript?
Uno, funciona en TypeScript, ya no necesitamos esto, funciona en TypeScript porque ahora TypeScript,
gracias a este código, está deduciendo, ¿vale?
Deduciendo que canvas es un HTML Canvas.
Aquí, ¿vale?
O sea, TypeScript lo está deduciendo, que aquí te refieres a HTML Canvas.
Pero lo bueno es que JavaScript, también JavaScript, está ejecutando el código de la condición.
Y por lo tanto, no entrará aquí si no funciona.
Esto es código JavaScript totalmente correcto.
Y si lo ponemos aquí, vais a ver que desaparece el error, ¿vale?
Así que es súper importante que entendáis que esto es clave si queréis evitar el error en tiempo de ejecución.
Así que esto es JavaScript puro.
Y con inferencia, TypeScript es capaz de indicar que esto, aquí dentro, es un HTML Canvas Element.
¿Lo habéis entendido ahora?
Pues es súper importante, ¿vale?
¿Cuándo usar instance of o type of?
Pues es súper importante.
La diferencia es type of para tipos, instance of para instancias.
Es así de claro.
O sea, por ejemplo, canvas es una instancia de HTML Canvas Element porque se hace con un new.
Pero no puedes decir, canvas es una instancia de un string, ¿sabes?
O sea, type of sería para strings, booleans, number, para tipos básicos.
Instance sería para instancias.
Por ejemplo, para saber si es una fecha, para el date y cosas así.
Otro tipo de aserción muy típica y para que sepáis, ¿no?
¿Cómo se haría un fetching de datos en TypeScript, ¿vale?
Fetching de datos en TypeScript.
Imaginad que tenemos esta API.
Voy a copiarme aquí una API que tengo por aquí.
API URL.
Esta API de aquí.
Que lo que hace es traernos todos los repositorios de GitHub que tenga la palabra JavaScript.
Y si le damos aquí, ¿vale?
Pues ves, aquí tenemos toda la información de JavaScript.
Pues aquí tenemos todos los repositorios de GitHub con toda esta información.
Claro, ¿cómo sabe TypeScript realmente que este es el tipo que tiene?
¿No?
Que lo que nos va a devolver es ese tipo.
No tiene ni puñetera idea.
Sigue claro.
¿Cómo haríamos el fetching de datos?
Bueno, esto ya lo deberías tener más que de memoria, ¿vale?
API URL.
Vale, ¿veis que este await no le gusta?
Porque dice, las expresiones await solo se permiten en nivel superior de un archivo
cuando el archivo es un módulo.
Para transformar un archivo en un módulo tenéis dos opciones.
Y una de ellas es, en lugar de utilizar .ts, podéis utilizar la extensión mts.
No sé si lo sabíais, pero ahora ya lo sabéis.
m de módulo ts.
Y la diferencia es que el .ts de forma nativa no podrías utilizar export e impost.
Y de forma, o sea, siguiendo la especificación.
Porque luego hay un montón de empaquetadores como bit, webpack, que te hace la magia y entonces no te das cuenta.
Pero de forma oficial, en realidad deberías utilizar .mts.
Y esto es una cosa que sigue, por ejemplo, no.js, ¿vale?
Entonces, tendríamos aquí a hacer el await del fetch.
Tendríamos la respuesta.
Si la respuesta es ok, pues hacemos algo.
Bueno, vamos a ponerlo al revés.
Si no es ok, throw new error request fail, por ejemplo.
Y luego, pues, tendríamos aquí que se ha ido todo bien.
Pues, transformamos esto a JSON.
Y tendríamos aquí la información.
Si miramos la API, veis, tenemos items.
Y dentro de los items, eso serían los repos, ¿no?
Y podríamos hacer un map de los items.
O sea, tendríamos aquí repos.
Sería data.items.map.
Y aquí tendríamos cada repo.
Y aquí tendríamos la información de cada repo y tal, ¿vale?
Esto sería un fetching de datos muy básico con TypeScript.
Muy básico, ¿vale?
Pero esto tiene razón.
Esto es particular de no, no de la especificación.
Me refería a la especificación respecto a hacer en más grid modules.
No la extensión, Marco.
Me refería de que la especificación,
el utilizar import y export en la especificación
solo es cuando son en más grid modules.
No de que la extensión es parte de la especificación.
Igual me lo he explicado mal, ¿eh?
Pero esa sería la explicación que quería decir.
Entonces, ¿crees que está bien?
¿Para la response con cosas que no vayas a utilizar?
Depende, depende.
Puede ser correcto, puede ser correcto.
Claro que sí.
¿Por qué?
Y de hecho, ahora lo vamos a ver, ¿no?
Esto como haríamos un fetching de datos básico en...
Uy, que no lo tenía música.
Esto como haríamos un fetching de datos básico en TypeScript.
Pero el problema lo tenemos aquí.
Fíjate que tú, si haces data.
Data.
No me está diciendo si algo está mal.
Yo intento acceder a esto.
¿Ves?
Esto debería estar mal porque esto no existe.
Pero no lo sabe porque data aquí tenemos que es any, ¿vale?
Nos está diciendo que el tipo es any, que puede ser cualquiera.
Y aquí tenemos el mismo tema de TypeScript.
Necesitamos decirle cuál es el tipo de datos que tenemos aquí porque no es capaz.
No es capaz de determinarlo.
No va a hacer el fetching de datos TypeScript.
Y va a decir, ah, sí, aquí tenemos este tipo de datos.
No tiene ni idea.
Así que lo que hace es, el response sí que sabe cuál es el tipo porque el fetch devuelve un response.
Pero cuando devuelve el response.json, data, puede ser cualquier cosa porque no sabe TypeScript.
Y nosotros le tenemos que indicar cuál debería ser el tipo.
A ver, podríamos hacer un montón de cosas.
Aquí, por ejemplo, deberíamos decir, bueno, el await response.json, esto tienes que tratarlo como si fuese, pues, un array, por ejemplo, de objetos, ¿no?
Podríamos decir, yo qué sé, item, tenemos la API response.
Y aquí tenemos items, que es un array de objects.
Podríamos ir paso a paso.
Y aquí podemos decirle API response es esto, ¿vale?
Y ahora sí, al menos, si hacemos data.punto, ¿ves?
Ahora sí que nos encuentra items.
Pero no lo está validando, ¿vale?
Es importante esto.
No lo está validando.
O sea, no sabe que realmente...
Esto es porque se está fiando de nosotros, no porque esté validando los datos.
Entonces, ahora podríamos utilizar esto.
Todavía nos quedarían un montón de cosas por validar.
Vamos a hacer esto bien.
Un truco que yo os diría para hacer esto es, en lugar de vosotros hacer manualmente esto, jamás hagáis esto manual porque es muchísimo trabajo.
Lo que tenéis que hacer es, vosotros vais a la API, en este caso, pues, esta.
Hacéis la petición, copiáis la respuesta y os vais a herramientas como QuickType.
QuickType, ¿vale?
Os vais aquí.
Y aquí abrís QuickType.
Y lo único que tenéis que hacer aquí es copiar aquí la respuesta.
Le decís el nombre, pues, aquí, en lugar de Pokedex.
Esto sería GitHub o GitHub API response, por ejemplo, ¿vale?
Y aquí, en lenguaje, pues, podéis elegir TypeScript.
TypeScript o TypeScript.
Y ahora os explicaré un poco la diferencia entre los dos.
Aquí podríais decir, ves que pone interfaces only, transform property next to JavaScript.
Aquí hay como diferentes cositas que se podrían hacer.
En lugar de utilizar en UMS, utilizar una cosa.
Otras, usar tipos en lugar de interfaces.
Esto lo veremos después, ¿vale?
Por ahora lo voy a activar porque todavía no os he explicado las interfaces.
Pero lo interesante de esto es que fijaos que esto os ha añadido todos y cada uno de los tipos de la API.
Así que esto ahora lo podríais poner.
Vamos a ponerlo aquí arriba, ¿vale?
¡Pum!
Aquí tendríais todos los tipos.
Aquí tenéis el GitHub API response.
Y esto ya directamente lo ponéis aquí.
Aquí en el...
Aquí, haz GitHub API response.
Y ya lo tenéis totalmente tipado.
Todo totalmente tipado, ¿vale?
Hay extensiones de Visual Studio Code que también nos hacen esto.
Pero si no queréis instalar nada con la app de QuickType, ya lo tenéis.
Y ahora ya hacéis data.items.
¿Veis que ya sale todo?
Punto.
Y aquí podríamos poner...
Bueno, ¿esto qué quiero hacer?
Quiero mapearlo, ¿vale?
Map.
Incluso este repo también está tipado ya, ¿vale?
Bueno, no se lee nunca porque no lo leemos.
Pero puedo hacer repo.
Punto.
Y aquí ya me dice todas las propiedades que tengo.
Y ya está.
Y ya te olvidas, ¿ver?
Repo ID.
Ya podríamos hacer aquí...
Pues yo qué sé.
Imagínate que quiero recuperar el nombre.
Sería repo.name.
La ID es repo.id.
Y así, además, si alguna vez, por lo que sea, intento acceder a algo que no existe...
Yo qué sé.
Link.
Pues veis, se va a quejar.
Va a decir, oye, que repo no existe en el tipo item que tú me has dicho aquí.
Así que si alguna vez necesitáis algún tipo de datos de un fetch y vais a utilizar la aserción de tipos,
lo mejor que podéis hacer es que lo haga totalmente automático, ¿no?
Aquí podréis hacer .html.url.
Este sería el correcto.
Y así continuamente.
Para eso es la aserción de tipos.
Pero, de nuevo, insisto en un detalle importante, ¿vale?
Antes de pasar con las interfaces, que vamos ahora.
Lo que os quiero comentar es una cosa que tenéis que tener clarísima es que,
aunque TypeScript no sé qué eje, esto no significa que esto sea seguro.
O sea, que a lo mejor la API de repente devuelve otra cosa, por lo que sea.
Y entonces, cuando tú intentas acceder a repo.name, te peta el JavaScript.
¿Por qué?
Porque no estamos validando los datos en tiempo de ejecución.
Para eso, fijaos que aquí tenéis uno que es TypeScript Zot, ¿vale?
Y vais a ver que aquí está haciendo como otro tipo de cosas.
Esto es código que sí que se ejecuta.
Y lo más interesante de esto, ¿ves?
Todo esto es un poco diferente porque esto utiliza una biblioteca y esto sí que ocupa, ¿vale?
O sea, para que veáis la diferencia.
Si yo este código lo pongo en el playground, ¿vale?
Fijaos el código en cuánto se queda.
En unas pocas líneas de código, no sé.
Y esto es porque, ya ves, los enums, me los está poniendo ahí a mano.
Si los enums los ponemos en const, ¿vale?
Si ponemos que esto es const enum, const enum, ¿vale?
Vais a ver que empieza a quitar un montón de código y casi no necesitar casi nada de código.
¿Vale?
Nos faltan los types, typeowner, const enum.
Vale, mira, este.
Y entonces no está haciendo ninguna validación.
En cambio, en esta de aquí, y por lo tanto esto en tiempo de ejecución tiene cero coste.
Pero en cambio, si le pones Zot, que es una biblioteca que hace validaciones de tipos
y que por lo tanto además te ayuda, como hace TypeScript, a validar los tipos.
O sea, que puedes hacer las dos cosas.
TypeScript detecta los tipos y además te los valida en tiempo de ejecución.
Si tú utilizas todo esto, vas a ver la diferencia.
Y la diferencia, pues es abismal, claro.
¿Ves todo el código que tienes aquí a la derecha?
Es porque todo esto sí que se ejecuta en JavaScript, ¿vale?
Así que es importante para que entendáis la diferencia de validar los datos en tiempo de ejecución
o no validarlos.
Y por eso es una de las grandes mentiras cuando se aprende TypeScript,
que mucha gente dice que en menos código, que se escribe menos código, es mentira.
Se escribe más código y potencialmente se puede ejecutar y puede hacer más lento tu código.
Pero se hace por una razón y es para validar los tipos de nuestros datos, ¿vale?
Para que lo tengáis en cuenta.
Que muchas veces la gente, no sé por qué, se pone a mentir con estas cosas y no tiene ningún sentido.
Muy bien, ya hemos visto los Types, ¿no?
Hasta ahora, pues hemos visto y podemos hacer el Type, por ejemplo, el Type de un héroe.
Vimos el Type de un héroe, ¿no?
Que era, yo qué sé, pues teníamos la ID, que era un String.
Teníamos, yo qué sé, el Name, que era un String, el Age, que era un Number, algo así, ¿no?
Y esto era para crear un Type.
Y podíamos tener el héroe, el hero, que era el tipo héroe, ¿vale?
Y podíamos crearlo, perfecto.
Y esto funciona correctamente.
Pero hay otra forma de definir contratos que tienen que seguir los objetos, ¿vale?
Y qué propiedades y métodos deben tener.
Incluso las clases y otro tipo de construcciones.
Pero en lugar de Type, podemos utilizar las interfaces.
Es muy similar, ya veis que son muy similares.
Se puede, muchas veces, el 90 y pico por ciento de las veces son intercambiables, ¿vale?
Pero tienen ligeras diferencias.
Esto hace exactamente lo mismo que estamos haciendo antes.
Le estamos diciendo la interfaz, le estamos diciendo básicamente que es una interfaz.
Porque muchas veces la gente, ¿qué es una interfaz?
¿Qué es una interfaz?
Mira, me gusta mucho un ejemplo.
No sé si conocéis el principito.
Seguro que sí.
A ver, el principito, el elefante.
Mira, vamos a ver un poco qué es una interfaz.
Y cuál es la diferencia para que lo tengáis clarísimamente.
Interfaz.
Mira, esta sería la interfaz.
¿Veis el principito?
Mira, lo de arriba sería la interfaz.
Y lo de abajo sería la implementación.
¿Por qué?
Porque arriba, o sea, la interfaz, claro, la forma que tiene,
la forma que tiene, es básicamente la forma que tendríamos que tener.
No sabemos lo que hay dentro.
No tenemos ni una puñetera idea.
Pero a lo mejor dentro, fíjate, hay un elefante.
Lo importante es que nosotros lo que estamos haciendo es como moldear cuál es el contrato que tiene que tener nuestro objeto.
Digamos que estamos poniendo como una forma y le tenemos que decir, mira, nuestro objeto tiene este name.
No sabemos cuál es el valor del name, pero sabemos que tiene que ser un string.
Sabemos que tiene un método que puede recibir estos parámetros y devolver estos.
Sabemos cómo es la forma, ¿no?
Por eso se le llama interfaz, porque es como el dibujo que está definiendo cómo es la forma de este objeto.
Pero no se está diciendo el objeto en sí.
Así que lo que tenemos que decir aquí es decirle, vale, sabemos la interfaz, la forma es que un héroe tiene esta forma.
Y ahora puedes hacer tantos héroes como quieras que puedan seguir la interfaz, ¿vale?
Así que esto sería como definir el contrato de un objeto para especificar sus propiedades y métodos.
Así que esto sea una interfaz.
Podemos hacer también un montón de cosas más.
O sea, podemos poner, por ejemplo, que tenga métodos también.
Por lo tanto, ahora veis que se nos está quejando porque no estamos poniendo aquí el saludar.
Pues tendríamos que ponerlo.
Console.log.hola porque no devuelve nada porque tiene void.
O sea, no está haciendo un return.
Entonces, las interfaces hasta este punto son muy similares a los type alias, a los aliases de types, de tipos.
Lo importante también es que las interfaces también pueden estar anidadas.
O sea, podemos utilizar una interfaz dentro de una interfaz.
Un ejemplo interesante, pues para que vayamos viendo.
Tenemos un producto con un número que tenemos en nombre, con un precio, ¿vale?
Esto es la interfaz producto.
Y la interfaz, dentro de la interfaz carrito de compras, podemos utilizar la otra interfaz.
Tendremos aquí el total price, que va a ser un número.
Y tenemos también aquí productos que va a ser un array de la interfaz producto.
¿Por qué?
Porque queremos tener, obviamente, los productos del carrito van a ser un array de esta interfaz que tenemos aquí.
Y ahora, si queremos crear un carrito de compras, pues tendríamos, bueno, que podríamos poner aquí quantity, ¿no?
Quantity con un number.
Y aquí, pues tendríamos que crear carrito, ¿vale?
Pues el carrito, carrito de compras, vamos a tener.
Esto tiene que ser el total price, que vamos a poner que tiene 100.
Y el producto tendría que ser un array, ¿vale?
El producto es un array.
Y aquí tendríamos que poner exactamente cómo es esto.
Una cosa muy interesante de TypeScript, al utilizarlo, es que os va a ayudar un montón también en el tema de rellenaros el código.
Porque detecta, ayuda mucho a detectar el código, ¿ves?
O sea, es que va automáticamente de iHackoPilot.
Y con esto ya tendríamos una interfaz dentro de la interfaz.
Esto también lo podéis hacer con los tipos, obviamente, ¿no?
Pero vamos un paso más allá, que esto es algo que no se puede hacer exactamente igual con los tipos a la hora de extender.
Y es que imagínate que tenemos el producto y, aparte del producto, vamos a tener algo más especializado, que va a ser una zapatilla.
Yo qué sé.
Pongamos interfaz, zapatilla.
Claro, alguien podría decir, bueno, vamos a copiar todo esto y, además, la zapatilla tiene la talla.
Pero esto no es necesario con las interfaces.
Lo que podemos hacer con las interfaces es extenderlas.
Una interfaz puede extender de otra.
Vamos a decir, vale, vamos a extender del producto.
De esta forma, ya no hace falta que pongamos todo esto porque está como extendiendo esta base.
Esta sería la base y lo que te decimos es, aparte, la zapatilla, además de todo esto, va a tener una propiedad concreta nueva llamada talla que va a tener el número.
¿Vale? Así que esta interfaz zapatilla, si ahora queremos crear aquí que este carrito de compras en lugar de producto sea de zapatillas, ¿ves?
Ahora nos va a decir que nos falta la propiedad talla.
Así que tendríamos que añadirle la talla.
Y hasta que no tenga la talla, no va a funcionar, ¿no?
Esto sería la diferencia.
Obviamente, los tipos también se pueden extender, pero no se puede utilizar de esta forma.
Y lo que se pueden hacer es unir, que esto lo llegamos a ver aquí, donde tú podías añadir, podías hacer intersecciones, por ejemplo, que cumpliese dos tipos o podías hacer que cumpliese uno u otro, uno de los dos tipos, ¿no?
Y es interesante y vais a ver que esto es una diferencia importante, aunque las podéis mezclar.
O sea, podríais decir, también podríais decir que cumpla aquí carrito de compra, que esto cumpla producto o el tipo más concreto, que es zapatilla.
Esto también lo podríais hacer aquí perfectamente, ¿vale?
O sea, ese operador que estaríamos utilizando con los types también lo podríais utilizar con las interfaces sin ningún tipo de problema, ¿vale?
Una cosa que está interesante, por ejemplo, aquí en carrito de compras.
Imaginad que queremos tener una interfaz con todas las operaciones que podemos hacer en el carrito de la compra.
Por ejemplo, carrito ops.
A ver, esto os lo comento, aunque también lo podéis hacer en los tipos, ¿no?
Que hay dos formas de indicar las funciones en las interfaces.
Tenéis esta, podéis poner product y aquí indicar void, ¿vale?
Y podéis poner remove, vamos, aquí y aquí.
Esto sería producto y lo hacemos así.
Podéis hacerlo así o otra forma que lo podéis hacer que, no sé, la que os guste más.
A mí me gusta más la primera porque lo veo más claro.
Pero otra forma que se pueden hacer las funciones es muy similar, muy similar, pero un poquito más corta.
Y es básicamente, ¿veis que aquí pones dos puntos, abres aquí y luego además le pones aquí una flecha?
Lo que puedes hacer es poner directamente el nombre del método, luego ya abres paréntesis, dos puntos, lo que devuelve.
¿Vale?
Son dos formas de hacer exactamente lo mismo.
¿Vale?
Pues aquí esto lo tendríamos.
Otra cosa que es interesante y que hay una diferencia importante respecto a los tipos y las interfaces lo tenemos con este error que veis aquí, ¿vale?
Veis este error que pone la interfaz carrito ops.
Aquí pone add remove clear.
Y aquí al intentar utilizar otra vez la interfaz, fíjate que me dice que está duplicado el identificador.
Pero no se queja, si aquí le pongo otra cosa, por ejemplo, imaginaos que lo dividimos en dos y esto lo ponemos aquí, ¿vale?
Fijaos que esto no peta.
Esto no peta y si ahora nosotros decimos, bueno, ¿y cuál es? ¿Qué es carrito ops?
¿No?
¿Qué es esto de carrito ops?
Si intentamos crear esto de carrito ops, veremos que tiene las dos.
O sea, carrito ops ahora va a ser carrito ops, vamos a poner operaciones ops, esto es carrito ops.
Pues vais a ver que son las dos cosas.
Lo que podemos hacer con las interfaces es escribirla una vez y luego escribirla otra vez.
A mí personalmente esto no me gusta.
No me gusta.
Yo, es una de las razones por las que no me gustan tanto las interfaces.
Y es que es muy fácil equivocarte en esto.
O sea, crear una interfaz, hacer como en otro sitio, después de 80 líneas, hacer otra cosa, ¿no?
Y de repente dices, vale, interfaz, carrito ops, en otro sitio, carrito ops y de repente que esté mal.
Y esto cuando es un proyecto bastante grande es más fácil de lo que parece.
O sea, lo que está haciendo aquí es extender automáticamente la interfaz esta.
Esto con los tipos no ocurre.
O sea, si tú intentas hacer esto con los tipos, ¿vale?
Imagínate que intentamos hacer esto con type, carrito ops, ¿vale?
Y, bueno, no se queja de que no tenemos producto, pero lo pego aquí en un momentito para que veáis.
¿Es una ventaja o una desventaja?
Esta, bueno, depende, depende de cómo lo veáis.
Pero aquí con los tipos lo que veis es que no podéis utilizar el mismo tipo dos veces.
Os dice, oye, tienes el tipo, lo tienes repetido, lo tienes duplicado.
Por lo tanto, tienes que eliminar uno de los dos.
En cambio, con las interfaces, esto es una de las diferencias más interesantes que tienen.
Esas interfaces y los tipos y no la comenta nadie tampoco, no sé por qué.
Pero es bastante importante saberlo, ¿no?
Es una herramienta, claro.
Al final hay que tener en cuenta que esto, si lo entiendes, que esto se ocurra, puede ser interesante sacarle partido.
O sea, puede ser interesante sacarle partido a esto.
Por ejemplo, puedes en diferentes archivos hacer esto.
A mí no me termina de gustar.
Pero bueno, cada uno, como lo vea.
Los tipos.
No puedes tener el mismo tipo dos veces.
En las interfaces, puedes tener dos veces la misma interfaz.
Y lo que hace es que se extiende automáticamente, ¿vale?
Importante la diferencia para que lo entendáis.
Muy bien.
Ahora que ya tenemos esto, para que lo veáis, ¿no?
Que se podía hacer como las dos cosas.
Las interfaces, igual que casi todo lo que hemos visto de TypeScript,
cuando se compila, queda en nada, ¿vale?
Fijaos, todo el código que tenemos aquí de producto, zapatilla, interfaz, no sé qué,
solo esta parte, que es una constante de JavaScript, es la que se queda aquí.
Todas las interfaces desaparecen directamente cuando se compilan a JavaScript, ¿vale?
Importante.
Tampoco se hace ningún tipo de validación.
Y ahora, la pregunta del millón.
¿Interfaces o tipos?
Después de ver lo que hemos visto, interfaces o tipos.
¿Cuál es mejor?
¿Cuál recomiendo?
¿Por qué la recomiendo?
¿Y cuándo usaría una?
¿Cuándo usaría la otra?
Bueno, como todo en esta vida, depende, todo depende.
Que según cómo se mire, todo depende.
Pero no os preocupéis que yo me voy a mojar, ¿eh?
Que decir depende lo más fácil y yo me voy a mojar.
En la documentación de TypeScript, fijaos que ya os explica de diferencias entre tipos y alias.
Aquí tenéis, ¿no?
Lo de extender las interfaces, que es una de las cosas que os he comentado.
También lo de añadir nuevos campos a nueva interfaz, ¿vale?
Hay algunas diferencias también a la hora de tipos de errores que hay.
Cosas que no pueden hacer unas u otras.
Por ejemplo, las interfaces no pueden declarar un tipo primitivo.
O sea, tú no puedes utilizar la interfaz.
Por ejemplo, una cosa muy chula que tenéis los tipos es que,
Imaginad que tenéis, bueno, como lo que hemos visto antes, ¿no?
Lo del RGB este.
Decir un tipo así.
Esto no lo puedes hacer con una interfaz.
Tenéis que, siempre está hablando de un objeto, ¿vale?
De una forma.
Entonces, eso no lo puedes hacer con interfaces.
Otra cosa muy interesante es cuando tenéis, por ejemplo,
si tenéis un tipo héroe, giro, ¿no?
Y tenéis aquí lo del string, name, age.
Imaginad que el string, pues, esto lo queremos separar.
Lo queremos separar en un concreto.
Esto con un tipo podéis hacer esto.
Y está muy bien porque si el día de mañana queréis cambiar solo esto,
directamente en este giro ya tenéis esto.
Entonces, imaginad que ahora esto, pues, pasáis a hacer,
pues, esto ahora va a ser un number y un string.
Algo así, ¿no?
Pues, esto fácilmente lo cambiáis, ¿no?
Pero esto, la línea 1, no la podéis hacer con una interfaz.
La línea 3, sí.
Esto puede ser una interfaz y quedaría exactamente igual.
Habría que quitarle igual y ya está.
Pero la línea 1 solo podría ser hacer con un tipo.
O sea, tipos más cercanos a un tipo primitivo no lo podéis hacer, ¿vale?
Es súper importante esto.
Entonces, aparte de esta diferencia que no se puede hacer una cosa u otra,
¿cuál es la mejor de las dos?
Yo diría que, en general, yo si me tuve que quedar con uno,
siempre intentaría utilizar tipos.
Siempre utilizaría tipos.
A mí los tipos me gustan un montón.
Creo que se entienden muy bien.
Son muy versátiles.
Además, no los puedes duplicar y todo este tipo de cosas.
Pero yo las interfaces, normalmente,
cuando estoy trabajando con objetos o con clases,
como que las identifico más.
Porque es un concepto que se identifica más
cuando hablamos de objetos o de clases y cosas así.
Así que, si tengo que utilizar una clase o un objeto,
hay veces que sí que puede ser que utilice una interfaz.
Pero para el resto, incluso a veces, incluso para objetos muy pequeños,
me gusta utilizar el tipo.
Eso es lo que te diría.
Que casi siempre utilizaría tipos, siempre que pueda.
Utilizo tipos y, a no ser que vea que sea necesario,
utilizaría la interfaz.
Eso es lo que haría yo.
Pero cada uno que haga lo que quiera.
Yo, por ejemplo, para las props de React,
a veces utilizo interfaz y tal, pero siempre que puedo, utilizo tipos.
Me gusta más el type que no el interface, porque me gusta más.
Me parece mucho más interesante y mucho más sencillo.
Y me da menos problemas.
Así que, ¿necesitas definir un objeto o un método de objeto
o la forma de una clase?
Interfaces.
¿Cuál es el beneficio?
Pues el beneficio de la fusión de declaraciones.
¿Cuándo utilizaría tipos?
Todo lo demás.
Pues para alias de tipos primitivos, definir tuplas,
definir uniones, crear, no sé, para sobrecargar funciones también.
Pues casi siempre utilizaría tipos.
Eso es lo que te digo.
Esa sería, ahí cada uno también hay un poco de subjetividad,
que hay gente que dice, no, siempre que es un objeto,
bueno, pues si lo quieres, pues hazlo así.
Otro concepto súper importante, Narrowing.
¿Qué es los Narrowings?
Vale, ya hemos hablado de los diferentes tipos que puede tener,
por ejemplo, imaginemos que tenemos una función,
vamos a poner aquí, una función mostrar longitud,
que le puedes pasar, no sabemos, ¿no?
Aquí le puedes pasar algo y puede ser un number o un string, ¿vale?
Y aquí tenemos mostrar longitud y le vamos a pasar el 1, por ejemplo.
Para mostrar la longitud, aquí podríamos hacer return objeto.le, ¿vale?
Pero claro, ¿cuál es el problema que tenemos aquí?
Que los números, si la ponemos esto igualmente, aunque pongamos esto,
fíjate que aquí se queja.
Porque dice, oye, la propiedad length no existe en el string number.
La propiedad length, la más específica es que dice,
la propiedad length no existe en el tipo number.
Esto le podéis llamar typewar, le podéis llamar de un montón de formas,
pero también de lo que se trata es de el Narrowing, ¿no?
¿Qué es lo que está pasando?
Lo que nos está diciendo TypeScript es, oye, ten cuidado porque objeto,
sí, cuando es un string puedes mirar el length,
cuando es un número no puedes mirar el length.
Y por lo tanto tienes que hacer un Narrowing,
que significa hacer como un embudo de que asegurarte
que vas perdiendo los tipos que no quieres controlar en este punto,
o sea, que no puedes utilizar en este punto.
Y aquí es muy sencillo, o sea, el ejemplo este es muy básico
y por lo tanto la forma de solucionarlo es, vale,
si el tipo de el objeto es un string,
entonces sí que voy a sacar la longitud del objeto.
Esto es muy parecido al ejemplo que hemos visto antes del canvas.
Al hacer el if, lo que hace TypeScript es detectar,
esto es código JavaScript, pero TypeScript lo está utilizando para decir,
ostras, ojo, que el objeto aquí me está diciendo que es string,
por lo tanto aquí este objeto ya solo es string.
Fíjate cómo cambia, de la línea 2 aquí,
que si me pongo encima, cuando hago el hover me dice,
objeto aquí en ese punto puede ser string o number.
Pero una vez que está dentro del if, como esto ha tenido que ser true,
ya TypeScript detecta que el objeto dentro del if solo puede ser string.
Y por lo tanto ahí ya sí que puedes utilizar todos los métodos de string, ¿vale?
Esto sería TypeWare o hacer un narrowing, ¿no?
Es decir, voy a asegurarme de que tengo el tipo correcto cuando estoy en esta línea.
Y aquí ya podríamos tratar que esto pues es un número.
Podríamos, de hecho, devolver objeto .toString y entonces .length, ¿no?
Ahora ya sabemos que esto no es un string, es un número, ¿ves?
Ahora ya sabe que es un número, porque en este punto,
si el código llega aquí, solo puede ser un número.
Esto sería una forma de hacer narrowing, ¿no?
Pero esta es muy básica.
Vamos a ver otra un poquito más avanzada, ¿vale?
Imaginad, por ejemplo, que tenemos dos interfaces.
Vamos a utilizar interfaces ya que estamos.
Tenemos a Mario Bros, que es del tipo Mario o tipo Nintendo o compañía.
Vamos a poner compañía.
Compañía.
Bueno, compañía, company, company.
Vamos a poner que es Nintendo, que su nombre, la interfaz puede ser string,
pues puede ser Mario, Mario Bros, Mario no sé qué.
Y lo que hace el Mario, sobre todo, es saltar, ¿vale?
Lo que hace es saltar, ¿ok?
Y vamos a tener también la interfaz de Sonic,
que la compañía, vamos a poner que siempre es Sega.
¿Por qué aquí no pongo string?
Pues porque las interfaces Mario, la compañía,
podemos decirle que siempre es Nintendo y punto, ¿sabes?
O sea, podemos indicarle el valor.
Y así nos aseguramos que si creamos un Mario,
la compañía siempre tenga que ser Nintendo.
No otro string, sino que siempre tenga que ser Nintendo.
Incluso puedes utilizar ideas y tal.
Esto para que lo sepáis, ¿eh?
Por eso no he puesto string.
Pero bueno, si queréis poner string para que no líe la cabeza.
Pero vamos a poner string.
¿Qué más?
El nombre puede ser Sonic, Sonic the Edge Joke,
pues un montón de formas.
Pero lo que hace este es correr todo el rato, ¿vale?
Y el personaje puede ser uno de los dos.
Puede ser o Mario o Sonic.
Fijaos cómo voy mezclando, ¿no?
Las interfaces con los types.
Es que es súper normal.
Así que cuando queremos mover o jugar, vamos a jugar.
Jugar, nos pasan un personaje.
He puesto persona y es personaje, perdón, ¿eh?
Personaje.
Si queremos utilizar el personaje, personaje, ¿vale?
Tenemos el personaje.
Aquí, hasta aquí, o sea, hacemos el console lock aquí.
Aquí podemos acceder al nombre.
Aquí no hay ningún problema.
Hay persona.
Personaje, personaje, ¿vale?
Aquí podemos acceder al nombre.
Fíjate que si yo aquí hago un autocomplete,
que no me va a salir.
Fíjate que me sale solo nombre.
Es raro que solo me salga nombre.
De hecho, company también me diría salir.
Pero no me va a salir correr.
¿Por qué no me sale correr?
No me sale correr porque en este punto,
TypeScript está diciendo, a ver,
company y nombre sí que puede ser porque
las dos interfaces que van a llegar están compartiendo esto.
Pero no puedes decir, no puedes ejecutar aquí correr o saltar.
Fíjate, si intento saltar.
Me va a decir, no puede ser porque no existe en el tipo personaje.
Porque Sonic no puede saltar.
Así que antes de hacer esto, asegúrate de que realmente tengas el tipo correcto.
Esto lo puedes hacer de diferentes maneras, ¿vale?
Una forma sería decir, bueno, es muy fácil.
Podrías mirar directamente si realmente llega a existir eso, ¿no?
O sea, podrías decir, si el typeof de persona, personaje, punto, correr,
existe, es una función, entonces sí que intento hacer esto.
Pero fíjate que esto me da problemas.
Esto lo vamos a solucionar después para que veas cómo arreglarlo.
Pero lo voy a comentar.
Otra forma de arreglar esto.
La forma buena que podemos decir es la que habíamos hecho antes.
Si sabemos que la compañía va a ser siempre Nintendo y aquí siempre va a ser Sega,
esto va a diferenciar las dos interfaces.
Y podemos utilizar esto para decir, vale, ya sé que si el personaje, la compañía, justamente, es Nintendo,
ya sé que dentro el personaje va a poder saltar.
Porque seguro que este es Mario.
No puede ser Sonic.
No puede ser Sonic porque la compañía es justamente Nintendo, ¿vale?
Y aquí seguro que solo llega cuando es Sonic.
Aquí ya seguro que solo llega a Sonic.
Bueno, aquí tendría que hacer un return, ¿vale?
Porque si no puede llegar Mario.
Pero ahora sí, ves que he hecho un return.
Ya el código solo llega aquí cuando sea Sonic.
Y esto lo hemos hecho justamente haciendo esto, ¿no?
Asegurándonos con un if que estamos controlando uno o con otro.
Es increíble el tema de la inferencia, ¿eh?
Las llamadas propiedades discriminantes.
Sí, aquí estamos discriminando si nos estamos refiriendo justamente a Mario o Sonic.
Aquí, ¿por qué no podríamos utilizar todavía InstanceOf?
No podríamos utilizar InstanceOf porque no estamos creando una instancia de.
Luego, cuando veamos las clases, lo podremos hacer, ¿no?
Entonces, si pones otro personaje en Nintendo que no pueda saltar, error.
Bueno, claro, si hacemos eso, sí.
Pero habría que hacer otra cosa.
¿Qué podemos hacer para arreglar esto?
Porque, claro, imaginad, hay gente que me dice, haz un typeof.
Es que el typeof aquí no funciona porque no sabemos si personaje,
realmente si el personaje no está llegando.
Podemos intentar hacer typeof, typeof persona.
Esto es Sonic.
Bueno, pues esto no cuela, ¿vale?
Estas cosas no funcionan.
Hay una forma en la que podríamos hacer esto sin necesidad de hacer esto de la compañía.
Imaginad que no tenemos la compañía.
Y solo tenemos la diferencia entre saltar y correr.
¿Cómo podríamos arreglar esto?
Bueno, esta es una técnica muy interesante y muy chula, ¿vale?
Gracias, Midu, por tomarte tu tiempo para explicar todo esto.
Gracias a ti, Jamie.
Espero que os sirva.
Oye, me voy a cobrar la hidratación que me ha pagado Juan Galúe, ¿vale?
Vale, una dice que es hacerlo opcional.
Imagínate que tampoco puede ser opcional.
Bueno, Rafael ha hecho un spoiler.
Rafael ha hecho un spoiler.
Pero bueno, está bien.
Me gusta que hagáis spoiler, ¿vale?
Rafael ha hecho un spoiler.
Vale, imaginad que queremos hacer esto que había hecho aquí.
Porque esto debería funcionar.
Oye, si mi personaje tiene correr, entonces, si es una función, entonces déjale correr.
¿Vale?
No quiero que me discrimines aquí entre uno y otro.
Vale, pues lo que podemos hacer aquí es decirle, es hacer una...
Hostia, ahora no me acuerdo cómo se llama esto.
¿Cómo se llama esto?
Ah, no me acuerdo.
A ver, ¿es type word?
¿Es type word?
No, pero type word sería...
Ah, a ver, es un type word.
Pero no me acuerdo si tiene un nombre esto, ¿vale?
No me acuerdo.
Si se acuerda de alguien.
Claro, type word sería en general.
Pero lo que vamos a hacer aquí es decirle, oye, ten en cuenta que aquí el personaje,
el personaje lo que va a ser aquí es...
Ten en cuenta que personaje es Sonic.
Aquí.
Personaje is Sonic.
¿Vale?
¿Y qué es lo que estamos haciendo aquí?
Ah, pues esto aquí no funciona.
Espérate.
Personaje is Sonic.
Correr.
Personaje es...
Ah, porque esto es la...
A ver, ¿cómo era esto?
Joder, el type word este me va a dar por saco.
A ver, ¿cómo es el type word?
Si me lo habéis puesto en los comentarios hace un momento.
Me lo habéis puesto en los comentarios.
También puede ser que sea la sintaxis de la función, porque estoy seguro que esto es así en la...
En esta, ¿no?
En la root function.
Personaje is Sonic.
A ver, algo he fallado con la sintaxis y no la veo.
A ver si me la ponéis bien.
Ponerme la sintaxis por ahí.
Debo devolver un boleano.
Debo devolver un boleano.
Ah, coño, claro.
Sí, tenéis razón.
Tenéis razón.
Tenéis razón.
Tenéis razón.
Que la he liado.
Que la he liado.
Tenemos que sacar esto, ¿vale?
Es que, claro, quería hacer el type word fuera.
Quería hacer el type word aquí.
¿Vale?
Type word aquí.
Vale.
Lo que podemos hacer...
Ahora tenéis toda la razón.
Joder, que se me había olvidado.
Que estaba alucinando.
Lo que queremos hacer es una función que nos diga si el personaje es Sonic o es Mario, ¿no?
Entonces, podríamos hacer una función aquí que sea function check is Sonic.
O check si puede saltar, ¿no?
Ahora.
Esto es lo que tenemos que hacer.
Tengo que hacer una función aparte.
Entonces, le vamos a pasar el personaje.
Y lo que le vamos a decir aquí es que, oye, quiero que me indiques si el personaje es Sonic.
Y el personaje va a ser Sonic si tratando al personaje como Sonic, realmente correr es diferente al Define.
Esto lo podéis hacer de diferentes formas.
No tenéis por qué hacerlo así.
Lo podéis hacer con el otro.
Y ahora, esto que habíamos hecho aquí, lo hemos extraído a esta función check is Sonic.
Le pasamos el personaje y ahora sí que esto lo podemos quitar, ¿vale?
Y ya está.
O sea, esto sería la Type Word, sería todo esto.
Lo que estamos haciendo es comprobar.
Lo que le estamos diciendo a TypeScript es, oye, da por sentado.
Da por sentado.
O déjame pensar.
O comprobar.
Comprobar si personaje es Sonic.
¿Por qué?
Porque si no nos deja comprobar, nos va a dar el problema, ¿no?
De correr y tal.
Lo que le estamos diciendo es, déjame comprobar si el personaje es Sonic.
Y esta función determina si es Sonic o no.
Entonces, ahora, gracias a esto, voy a poder chequear que el personaje es Sonic y voy a poder correr.
¿Vale?
Y esto, de otra forma, sería mucho más complicado de hacerlo.
Ya veis que si tenemos la compañía es muy fácil.
Si teníamos otra propiedad que discrimina cada tipo sería muy fácil.
Pero aquí lo que estamos haciendo es básicamente crear una función que está discriminando el tipo.
Y lo hacemos a través de una propiedad que no veíamos si existía o no.
Estamos diciendo, oye, si personaje, damos por sentado que es Sonic, porque fijaos que si no le decimos esto.
¿Veis?
Claro, personaje no puedes acceder a correr.
Y lo que hacemos aquí es decir, bueno, voy a utilizar una aserción para dar por sentado que es Sonic,
porque es el único que puede correr, pero lo único que voy a hacer es comprobar si es undefined o no.
Y de esta forma voy a poder discriminar.
Porque si puede correr, pues será Sonic y podré correr.
Y ya está.
¿Vale?
Está bien discriminar en el código.
Sí, fuera del código no discriminéis.
Si hay más de un personaje, tengo que hacer una validación para cada uno.
¿No hay una manera más rápida?
A ver, podríais hacer...
Claro que hay maneras más rápidas.
Normalmente se discrimina mejor con el instance of.
Lo podéis hacer con un montón de cosas.
Lo de personaje y Sonic, ¿qué significa?
Esto es lo que le está indicando, básicamente, que lo que estamos haciendo es determinar en esta función si personaje es Sonic.
Y por eso se llama una type word.
¿Vale?
Type word.
Porque esto va a hacer entender a TypeScript, ¿ves?
Le está haciendo entender que al utilizar esta función va a saber si personaje es Sonic o no es Sonic.
A ver, ahora, ahora bien.
Esto lo explico, pero, pero, esto hay que evitarlo.
¿Vale?
Esto sería en el caso de necesitarlo.
Pero siempre que podáis, los type words hay que evitarlos.
¿Vale?
¿Por qué?
Porque hace que vuestro código sea mucho más verboso, que tengáis que hacer demasiadas comprobaciones.
La comprobación, obviamente, sí que se hace en tiempo de runtime porque esto es JavaScript.
Esto es JavaScript.
Y, por lo tanto, evitaría problemas en el código.
Y está bien porque así os va a evitar un montón de petes.
¿Vale?
Pero siempre que podáis, yo lo evitaría.
En este caso no funciona en instance of.
Y no funciona porque no hemos creado una clase.
Pero ahora vamos a ver un ejemplo de, por ejemplo, una clase.
Pero antes de ello, antes de esto, dejadme que os enseñe un ejemplo que vais a entender el tipo never mejor que nunca.
Y es que está muy interesante porque aquí lo tenemos.
Fijaos.
Mira.
Tenemos que personaje, aquí, personaje es Mario o Sonic.
¿Vale?
Entonces, aquí chequeamos si el personaje es Sonic.
¿No?
Por lo tanto, el personaje aquí será Sonic y puede correr.
Si no, ¿qué será aquí el personaje?
Aquí solo puede ser Mario, ¿verdad?
Aquí solo puede ser Mario.
En el else solo puede ser Mario.
Vamos a poner aquí un return, ¿vale?
Y aquí un return.
O sea, o corremos o saltamos.
Punto.
No hay más.
O corremos o saltamos.
Ahora bien.
Entonces, aquí personaje, ¿qué es?
¿Qué será?
Sonic o Mario.
Vamos a ver qué es este personaje.
Bueno, este personaje, en realidad...
Hostia, sí que me está poniendo...
¿Por qué?
Hostia, pues aquí yo pensaba que...
Ah, bueno.
Podemos poner...
Podemos poner aquí...
Sí, personaje, nombre...
Es Mario saltar.
Me ha dejado fatal.
Pero aquí personaje...
Hostia.
Aquí personaje debería ser Never.
No sé por qué me dice que es Mario.
Bueno, porque aquí a lo mejor...
Bueno, vamos a poner...
Si no es Sonic, vamos a poner aquí.
Si no es Sonic, vamos a decir que se va a saltar.
Y aquí debería ser Never.
Pero me está diciendo esto.
Se está yendo a la malla.
No tienes que poner...
Ah, bueno, es que aquí se nos va el código.
A ver, aquí...
No, no, pues tampoco.
Pues aquí debería poner que esto era Never.
Y me está diciendo que es Mario o Sonic.
La madre lo parió.
La madre lo parió.
A ver, con un ejemplo básico...
Un ejemplo básico esto nos tiene que salir.
O sea, si tenemos una función que tenemos un string y un number,
pongamos esto, y el tipo de X es string,
esto aquí tendemos...
Tendemos...
Yo qué sé.
Aquí es DoSomething.
Vale.
Si decimos que...
Si no, el type of X, si es number,
aquí hacemos un DoSomething.
Y el tipo...
Y esto debería ser Never.
O sea, aquí...
¿Qué pasa?
Que si le estamos diciendo...
Esto debería ser Never.
Esto debería ser Never.
Que X...
¿Ves?
Aquí sí que sale el Never.
No sé por qué no me ha salido con el otro.
No sé si a lo mejor alguna comprobación no está haciendo bien.
Pero básicamente es...
¿Ves?
Aquí entrará cuando X...
X es string.
Y por lo tanto aquí puedes hacer X to upper case.
Porque ya sabemos que es un string.
Aquí el número podemos hacer to fix.
¿No?
Podemos hacer to fix porque aquí X es un número.
Pero en este else,
la X será Never.
Porque según los tipos que le hemos indicado,
nunca debería llegar aquí.
¿Sabes?
O sea, nunca llegará aquí.
Porque o es string o number.
Y aquí X es Never.
Porque nunca llega aquí.
Y ese tipo...
O sea, es Never.
Entonces, no es...
No puede ser un...
O no.
Si le pones un known,
ya no deja de funcionar.
No tiene sentido.
Porque ya podría ser otra cosa, ¿no?
Entonces...
Ah, hasta cierto punto existe Mario & Sonic.
Ya, pero no entendía muy bien por qué aparecía eso.
Pero bueno, aquí tenéis un ejemplo del Never.
¿Vale?
Ahí tenéis un ejemplo del Never.
Del Never.
Bueno, vamos a poner otro ejemplo para que veáis lo de Instant Soft que os decía antes.
Vamos a poner el ejemplo de un Avenger.
Vamos a crear un Avenger.
Tengo por aquí una clase.
Vamos a hacer esto.
A ver, esto hasta aquí.
Vamos a hacer una clase que sea de JavaScript, ¿no?
Esto sería JavaScript.
Pero ya veis que se nos queja porque una clase Avenger con su constructor, con un getter, un setter...
Y se nos está quejando porque le faltan los tipos.
Para tipar una clase, una cosa que podéis hacer es directamente poner las propiedades aquí.
Podéis decirle, oye, el nombre es un string, el powerScore es number, powerScore es number...
Y aquí tendríamos el número de batallas que ha ganado, ¿vale?
Y podéis ponerle un valor inicial, por ejemplo, esto.
Y con esto ya lo tendríais tipado la clase.
También lo podéis hacer con interfaces, por ejemplo, ¿no?
Pero con esto ya podríais hacer Avengers, New Avengers y crear vuestro Avenger.
En este caso, yo qué sé.
¿A quién creamos?
A Spidey.
Y le decimos que 80 es el powerScore y ni siquiera...
¿Avengers?
Ah, Avengers.
Es Avenger, ¿vale?
Un nuevo Avenger.
Y ya con esto, fijaos que hacéis Avengers punto y no sé por qué a veces...
Y ya lo tenéis todo.
Ya no tenéis que hacer absolutamente nada más.
Ya lo tenéis así perfectamente con el power y tal.
Pero hay cosas interesantes que podéis llegar a hacer con las propiedades en TypeScript.
Por ejemplo, el name.
Imaginad que tenéis al Avengers punto name y ahora le podemos cambiar a Hulk.
Pero esto no tiene sentido.
Spidey de repente ahora se llama Hulk.
Le hemos cambiado.
Hemos mutado la clase y por lo tanto, si hacéis un console log de Avengers, vais a ver que
ahora se llama Hulk.
Cuando en realidad el nombre debería ser Spider-Man.
Spidey, ¿no?
Porque hemos mutado la clase.
Para esto podemos hacer que sea de solo lectura.
Podemos decir que esto sea solo lectura.
Y fíjate que ahora se me queja, ¿no?
Otra cosa interesante que podéis hacer, por ejemplo, el powerScore este que tenemos
aquí, este powerScore podemos decir que sea privado.
Tenemos dos formas de hacer esto.
Uno, la forma de JavaScript.
La forma de JavaScript sería esta.
Es ponerle el hash.
Y fíjate que aquí se nos queja un montón porque dice la propiedad no existe porque
tenemos que poner el hash por todos los sitios, ¿vale?
Podemos el hash por todos los sitios.
Y esto ahora lo que va a hacer es que solo de forma interna podamos acceder.
Si ahora intentamos acceder a Avengers.
PowerScore es que no existe.
El PowerScore no existe porque es privada, ¿vale?
Esto lo que hace es que sea una propiedad privada y solo dentro de la clase podamos acceder
a ella.
Pero también tenemos la forma, esta sería la forma oficial de JavaScript y ten en cuenta
que si haces esto, aquí, bueno, aparte de transpilarte un montón de cositas aquí,
vais a ver que en realidad sí que hace que la clase sea privada, ¿veis?
Lo pone por aquí.
La forma de TypeScript para que no funcione en Runtime sería utilizar aquí, por ejemplo,
el private.
Y esto tiene cosas buenas y malas, ¿vale?
La cosa buena es que te puedes referir a ello sin necesidad de utilizar el hash, que
también la propiedad va a ser totalmente privada, ¿ves?
La propiedad PowerScore es privada y solo se puede acceder a ella en la clase.
Tampoco vais a, ni vais a poder acceder, ni vais a poder hacer nada.
Pero lo malo que tenéis que tener en cuenta de esto es que este private no lo va a transpilar.
O sea, esto es solo para, de forma estática.
¿Vale?
¿Veis?
Aquí en este caso ves que este PowerScore se está quedando, aunque el PowerScore hemos
puesto que es privado, en realidad en JavaScript no es privado.
O sea, lo deja, solo está haciendo la comprobación de forma estática.
Puede ser bueno, malo, lo que tú quieras.
Depende de cómo lo quieras ver.
También puedes hacer que sea privado y read-only.
Puedes hacer las dos cosas.
Por ejemplo, aquí private, puedes hacer private y read-only.
Puedes hacer las dos cosas.
Y ahora este warm battles, pues, es privado y además solo de lectura.
Así que solo lo podríamos inicializar en un punto y ya está.
Esta podría ser una cosa.
Puedes utilizar dos, incluso private, read-only.
Por defecto, si te estás preguntando, bueno, ¿y qué más hay?
Por defecto tendrías el public.
El public es el que tienes por defecto.
Si no pones nada, sería el public.
Y otro más que tienes sería protected, que es una especie de privado.
Esto es algo muy típico de clases.
Si has hecho clases y programación orientada a objetos, pues, ya te sonará.
Pero el protected es algo parecido a que es privado, pero puedes acceder también a clases que heredan de esta clase, ¿vale?
Por eso está protegido.
No puedes acceder en instancias de la clase, pero sí puedes acceder a ello en clases que están heredando de ello, ¿vale?
Así que ahí tendrías un poquito la diferencia.
Y esto serían un poco las clases.
Para las clases también podríais utilizar interfaces, ¿no?
O sea, podéis utilizar aquí interface.
Podrías tener, bueno, giro, si le gusta giro.
Bueno, no sé por qué ahora utiliza este, ¿vale?
De age.
Bueno, no me está haciendo este.
Vamos a poner interface avenger, por ejemplo.
¿Vale? A ver si me lo hace.
Name, el power score, el one battles, el age y ya está, ¿no?
Y esta interfaz, le podéis decir que esto implementa la interfaz de avenger, ¿no?
Aquí vamos a tener algunos problemas porque no son exactamente igual.
Porque, ¿ves? Todas declaraciones de name deben tener modificadores idénticos y no estamos teniendo los mismos modificadores.
Aquí tendríamos que empezar a quitar.
Esto ni siquiera sería necesario ahora.
Lo podríamos quitar.
Pero lo importante de esto es que esta interfaz está como describiendo cómo es el avenger.
Y, por lo tanto, ahora no te puedes transformar.
No puedes hacer aquí decir, por ejemplo, yo qué sé.
¿Veis?
He puesto un punto y ya los detecta.
Pero aquí no te puedes inventar cualquier cosa porque esta propiedad no existe en esta interfaz.
Y estamos diciendo, oye, voy a crear una clase que implementa la interfaz avenger, ¿vale?
Vamos a poner avenger's interface, por ejemplo.
No me gusta el nombre interface.
O sea, creo que tiene más sentido este.
Que le pongas avenger directamente y que tengas una clase que implementa la interfaz.
Y a lo mejor le puedes cambiar cómo sería avenger hero, lo que sea.
O avenger, lo que tú quieras, ¿no?
Pero lo interesante es que al implementarlo te aseguras y lo estás separando.
Esta sería la parte de la implementación.
Mucho más con código y la interfaz la tendrías separada.
Y lo mismo podrías hacer incluso con métodos.
O sea, podrías tener aquí uno que sea, yo qué sé, battle, ¿no?
Que sea una función con un enemy que te diga esto.
Y esto lo podríamos implementar aquí.
Podríamos tener el battle.
Y aquí, fíjate que ya podríamos tener, pues, battle, que le pasas el enemy.
Que sea otro avenger, un poco raro.
Y nada, pues aquí, pues, si gana, pues, que ha ganado la batalla y sube su nivel.
Y si no, pues, hacemos esto y hacemos esto y tal, ¿no?
Podríamos llegar a hacer este tipo de cosas.
Vamos a quitar esto por aquí.
Y ya lo tendríamos.
¿Vale?
Battle está duplicado porque...
Battle duplicado.
¡Hostia!
¿Por qué me está haciendo esto?
He hecho algo regulinchis porque al hacer la implementación de la interfaz, no tendría que hacer esto.
O sea, porque...
Ahora me ha dejado flipando.
Es muy común utilizarla ahí, esto.
A ver, no lo recomiendo porque no me gusta, ¿no?
Porque es un poco raro.
Pero, no sé, si os gusta para diferenciarlas y tal.
Es verdad que hay gente que no recomienda que lo hagamos porque como que queda muy claro ya que las interfaces...
Lo mejor que podéis hacer es exportar las interfaces y tenerlas separadas en un sitio.
O sea, podéis tener un archivo aparte que tenéis aquí y normalmente ponéis types.d.ts, exportáis esto y directamente aquí importáis el tipo Avenger directamente desde los tipos, ¿no?
Pero si le queréis ponerla ahí para que sea la convención que creo que hay algunos...
Vea, podéis utilizarlo aquí.
Hay algunas...
Aquí, vamos a ponerlo por acá, por aquí.
Declaraciones.
Fijaos que cuando he creado esto, cuando he creado este...
Implementa ahí Avenger...
Lo que he hecho aquí, cuando he hecho esto de crear el archivo, fijaos que he puesto un .d.ts, que muchas veces la gente me dice, oye, ¿por qué el .d.ts?
Esto es una convención en la que estamos poniendo la definición, ¿vale?
Donde tenemos el archivo con todas las definiciones.
Cuando tenéis todas las definiciones en el mismo sitio, lo que hacéis es ponerle .d.ts.
Y, por lo tanto, esto aquí no debéis tener código normal, ¿vale?
No debéis tener código normal.
Porque si no, fijaos que se queja, ¿no?
Dice, las declaraciones de nivel superior de los archivos deben comenzar con modificador, declare, o export, no sé qué.
Entonces, esto, como lo que entiende directamente, es que estamos utilizando un archivo donde vamos a tener todo declaraciones.
Vamos a tener interfaces, puedes tener tipos, por ejemplo, type.
Puedes tener lo que sea.
Pero no pongas aquí código.
Y está bien que lo tengáis separado porque, obviamente, si lo queréis reutilizar en cualquier sitio, pues os va a ayudar un montón, ¿vale?
d.de.medudev. No, d.de.definitions.
Sería eso, ¿no? d.de.definitions.
Y una propiedad privada después del implements, una propiedad privada.
No habría ningún problema.
O sea, si tenemos aquí una propiedad esta, ¿no?
Private.
Y private, no sé qué.
O sea, espérate, porque a declaración final cannot be imported without no sé qué, no sé cuánto.
Esto es porque he utilizado esto, ¿vale?
Y Avenger, PowerScore.
No existe en el tipo Avenger, PowerScore.
Pero sí que existe, ¿no?
Está aquí.
No existe en el tipo Score.
A ver.
A ver.
Avenger.
Implenta de forma incorrecta.
Le faltan las propiedades siguientes del tipo.
Name, PowerScore.
Vale.
Vamos a poner los name, PowerScore, OneButters, H.
Ah, porque estas las tenemos que poner aquí.
Es que si no están aquí, PowerScore, Number, OneButters.
El PowerScore ya lo tenía puesto.
Si no aparecen aquí se me va a quejar.
Yo creo que con esto, ah, no, se me va a quejar igualmente.
Pues nada, las ponemos ahí y ya está.
Y ahora sí que lo tiene bien implementado, ¿vale?
Y decías lo de read only, no sé qué, ¿no?
Read only.
¿Ves?
Esto lo puedes poner aquí sin ningún problema.
O sea, no tendrías ningún problema de ponerlo.
Y aquí, pues, podrías ponerlo también.
En TypeScript hay herencia múltiple.
Te refieres a si puedes implementar más de una interfaz.
Sí que puedes implementar más de una interfaz.
Y TypeScript tiene la herencia que tendría exactamente JavaScript.
O sea, puedes hacer exactamente la misma.
Lo que no puedes...
A ver, a la hora, piensa que como las interfaces.
O sea, lo puedes lograr no implementando múltiples interfaces,
sino creando una interfaz que al final extienda de diferentes interfaces.
Entonces ya lo tendrías, sería exactamente lo mismo, ¿no?
Es que el implement no agrega los atributos de JavaScript de la clase.
Eso hay que hacerlo igualmente a mano.
Claro, exactamente.
¿Cómo tipar un objeto que en su interior tenga propiedades dinámicas?
Un objeto, cursos, que como propiedad tenga solo un curso.
Si son dinámicas, significa que pueden ser opcionales.
Si son opcionales, pues así es como lo tienes que hacer, ¿no?
Y al final lo que puedes tener es tener como más de una cosa y ya está.
O sea, podrías tener un tipo que le falten ciertos...
Por ejemplo, un curso.
Puedes tener el input de un curso que todavía le faltan algunas propiedades.
O sea, el curso puede estar en diferentes estados y cada uno de esos estados con diferentes propiedades
pueden ser diferentes tipos.
Y a mí me parece bastante interesante que lo podáis hacer así.
O sea, puede ser un hero input, un héroe que todavía sea junior, a lo mejor tiene diferentes propiedades, cosas así.
Y al final lo que puedes hacer es utilizar cada uno de ellos cuando lo necesites.
Pues nos quedamos aquí porque es que nos quedan dos temas.
Los genéricos y los utility types.
Y yo creo que eso nos da porque hay partes, por ejemplo, utilizar el partial y tal.
Lo podemos hacer en la siguiente clase.
¿Qué tal?
¿Os ha gustado?
Porque, por ejemplo, en la primera clase vi que hubo bastante más gente.
Creo que cuanto más vamos haciéndolo como más avanzado, como que se va mucha más gente.
No sé si seguir haciendo contenido así que sea tan avanzado porque si no, al final, no sé qué hacer.
No sé qué hacer.
La gente se me asusta muy fácil.
Midus, ¿estás pasando por props una propiedad o una interfaz o una interfaz?
¿En el hijo tienes que volver a declararla?
No.
Soy una persona que no me gusta hacer mucho spam y entonces solo hago una vez.
Y me sabe mal.
He hecho cursos de muchas horas y este detalle no se explica.
Lo has hecho pulgar hacia arriba.
Lo he hecho pulgar hacia arriba.
Bueno, muchas gracias a todos.
Gracias, Kaliser, Draox.
Muchas gracias, Space, por la sub.
Muchas gracias a todos los que han suscrito.
Os quiero mucho.
Espero que hayáis aprendido algo nuevo.
Hayáis aprendido algo de TypeScript que os sirva.
Y que así tenéis un poquito menos de miedo de TypeScript.
Así que, cuidado mucho.
Nos vemos.
Chao.