# Typescript (_TS_) ![ts-portada](https://i.imgur.com/DMTjI8x.png) ## Introducción ### ¿Qué es Typescript? _TypeScript_ (ts) es un lenguaje de programación libre y de código abierto desarrollado y mantenido por Microsoft. Es un superconjunto de _Javascript_, que esencialmente añade tipos estáticos y objetos basados en clases. ### ¿Para qué sirve Typescript? _Typescript_ trata de resolver todos los posibles errores de _Javascript_ en el momento en el que se escribe el código _Javascript_ al proporcionar un tipado estático y encapsulación para generar un código libre de problemas. _Typescript_ en realidad es un compilador de _Javascript_ que convierte el código _Typescript_ a _Javascript_ con la certeza de que el código funcionará de la forma correcta. Con _Typescript_ es posible identificar errores en el momento en el que se esta escribiendo el código, antes de compilar el código o realizar pruebas. ### Ventajas de Typescript 1. Lenguaje tipado 2. Opciones adicionales de JS #### 1. Lenguaje tipado A diferencia de _Javascript_ que es un lenguaje débilmente tipado, _Typescript_ es un lenguaje con tipado estático, es decir, es necesario incluir el tipo de datos en variables, funciones, parámetros, entre otros. El objetivo principal de _Typescript_ es identificar errores relacionados con el tipo de datos señalarlos antes de la compilación para que dichos errores sean solucionados. #### 2. Opciones adicionales de JS _Typescript_ además de proporcionar tipos de datos, provee de otras carácteristicas adicionales como diversas estructuras de datos, interfaces y elementos avanzados relacionados con el DOM. ## Tipos de datos Al igual que _Javascript_ en _Typescript_ existen diferentes tipos de datos como: - Números (_numbers_) - Cadenas (_strings_) - Booleans - Objetos (_objetcs_) - Arreglos (_arrays_) Los tipos de datos anteriores los hemos visto anteriormente en la guía de [Javascript (JS)](/00MnMAgtQlWqRoexWxBK7g?both). En _Typescript_ para asignar el tipo de dato en la declaración se hace de la siguiente forma: ``` let age: number; let name: string; let canVote: boolean; ``` En el caso del arreglo, se específica el tipo de dato de los elementos del arreglo: ``` let nums: number[]; let names: string[]; ``` Aunque si en la declaración de la variable se realiza la asignación, no es necesario incluir el tipo de dato. Asimismo, _Typescript_ añade otros tipos de datos como: - Tuplas (_Tupple_) - Enumeración (_Enum_) - Alguno (_Any_) - Desconocido (_Unknown_) Abordaremos estos tipos de datos a detalle: ### Tuplas (_Tupple_) Las tuplas (_tupple_) son una secuencia de valores agrupados como si se tratarán de un único valor. Una vez que se declara una tupla (_tupple_) no puede ser modificada. Ejemplo: ``` let myTupple: Tupple; myTupple = [3, 'Apples']; ``` Como podrás notar una tupla es similar a un arreglo, por lo que, para acceder a las propiedades de una tupla, podemos hacerlo mediante el índice: ``` console.log(myTupple[1]); //output "Apples" ``` ### Enumeración (_Enum_) El tipo de dato _enum_ se utiliza para otorgar un valor númerico y con ese número identificar un valor en específico, es algo similar a otorgar un índice. Ejemplo: ``` enum Role { READ_ONLY, CLIENT, ADMIN } let user = { name: "John", lastname: "Doe", role: Role.ADMIN } console.log(user.role); //output 2; ``` ### Alguno (_any_) _Typescript_ contiene un comodín cuando no se especifica el tipo de dato o cuando el tipo de dato no es relevante. Para ello, hace uso del tipo de dato _any_: ``` let randomVariable: any; ``` **Nota:** En _typescript_ cuando en una variable no se específica el tipo de dato, por defecto _Typescript_ le otorga _any_. En el caso de un arreglo con elementos de tipo de datos distintos, podemos declararlo como tipo de dato _any_: `let mixedArray: any[];` ### Desconocido (_unknown_) Por otro lado, existe el tipo de dato _unknown_ que es básicamente el mismo que _any_ con la diferencia de que con _any_ puedes puedes asignar un valor _any_ a una variable _number_, _string_ o _boolean_. Pero con _unknown_ no puedes asignar un valor _unknown_ a una variable _number_, _string_ o _boolean_. Ejemplo: ``` ✅ let someVar: any; ✅ let someNumber: number; ✅ someVar = 5; ✅ someNumber = someVar; ✅ let someVar2: unknown; ✅ let someNumber2: number; ✅ someVar2 = 5; ❌ someNumber2 = someVar2; ``` ## Casting ## Funciones con tipo de dato en el parámetro En _Javascript_ los parámetros de las funciones pueden ser de cualquier tipo de dato, pero no es lo mejor debido a que en ocasiones los usuarios no pueden pasar los valores correctos en los parámetros. Por ejemplo, analicemos la siguiente función de suma: ``` function sum(num1, num2) { const res = num1 + num2; return res; } ``` En la función anterior estamos esperando dos valores de tipo _number_, como por ejemplo `sum(5,3)`, con este ejemplo el resultado de llamar a la función sería 8. Pero, qué pasaría si en lugar de _numbers_ le pasamos a la función _strings_ como parámetros, por ejemplo `sum("5", 3)`, el resultado de la llamada a la función en el ejemplo anterior sería 53, claramente ese no es el resultado que esperamos. Con _javascript_ podríamos solucionar ese problema con lo siguiente: ``` function sum(num1, num2) { if(typeof num1 === 'number' && typeof num2 === 'number') { return num1 + num2; } else { return parseFloat(num1) + parseFloat(num2); } } ``` Pero con _typescript_ podemos solucionarlo de una forma más sencilla, al proporcionar el tipo de dato en los parámetros de la función: ``` function sum(num1: number, num2: number) { return num1 + num2; } ``` En el ejemplo anterior, se le asigna el tipo de dato _number_ a los parámetros num1 y num2. Por lo que, si se intenta llamar a la función con un parámetro que no sea _number_, _typescript_ no permitirá llamar a la función y arrojará un error. `❌ sum("5", 3);` ## Union Types _Typescript_ permite que en los parámetros se pueda definir más de un tipo de dato. Tomemos el ejemplo anterior, si quisieramos diseñar una función para concatenar dos números (_number_) o dos cadenas (_string_), con el código anterior al pasar dos cadenas como parámetro _typescript_ nos regresaría un error. Para permitir que la función _sum_ pueda concatenar tanto _strings_ como _numbers_ podemos hacer uso de los _union types_, con los cuales le diremos a _typescript_ que puede recibir tanto un _string_ o un _number_, aquí un ejemplo: ``` function sum(param1: number | string, param2: number | string) { return param1 + param 2; } ``` Con lo anterior podríamos mandar a llamar a la función _sum_ de la siguiente manera: ``` const myNumber = sum(5+3); const myString = sum("Hello ", "World"); console.log(myNumber); //output 8 console.log(myString); //output "Hello World" ``` ## Literal Types Por otra parte, _typescript_ además de permitir en los parámetros dos tipos de valores, también permite ser más especifico al poder determinar valores especificos en los parámetros. Por ejemplo: ``` function convertGradesTo(grades: number, currentUnit: 'c' | 'f') { let res; let changeTo; if(currentUnit === 'c') { res = grades * (9/5); changeTo = 'Fahrenheit'; } else { res = (grades - 32) * (5/9); changeTo = 'Celcius'; } return `The temperature in ${changeTo} is: ${res}º`; } let conversion = convertGradesTo(23, 'f'); console.log(conversion); //output "The temperature in Celcius is: -5º" ``` Como podemos observar en el ejemplo anterior, el parámetro _currentUnit_ podría ser `c` o `f`, pero no aceptaría un valor diferente al declarado en el parámetro. `❌ convertGradesTo(23, 'k');` ## Type Aliases Asimismo, _typescript_ permite crear tipos de datos basados en los _literal types_ con la finalidad de hacer el código más limpio o implementar estos tipos de datos específicos en diferentes archivos _ts_. Para declarar un _type alias_ se debe hacer uso de la palabra reservada _type_ aquí un ejemplo: ``` type Combinable = number | string; function potential(base: Combinable, exp: Combinable) { const res = (+base) ** (+exp); return res; } const myPot = potential(5,'3'); console.log(myPot); //output 125 ``` En el ejemplo anterior, creamos un tipo de dato nuevo llamado _Combinable_ que puede ser _number_ o _string_. ## Return Types Por otra parte, es posible asignar un tipo de dato al valor de retorno de la función, algo similar a lo que sucede con los parámetros de la función. Retomemos, el ejemplo de la suma de los _numbers_, para determinar que la función se realice correctamente y se retorne un número, delante de los parámetros colocaremos el tipo de dato que debe regresar la función. Ejemplo: ``` function sum(n1: number, n2: number): number { return n1 + n2; } ``` ### Vacio (_void_) En caso de que no se retorne ningún valor en la función, indicaremos el tipo de dato _void_. Ejemplo: ``` function showAlert(message: string): void { window.alert(message); } ``` ## Interfaces (_interface_) Una interfaz es un conjunto propiedades y métodos cuya funcionalidad es la de determinar el funcionamiento de una clase, es decir, funciona como un molde o como una plantilla. Una interfaz se debe declarar con la palabra reservada _interface_ delante de la palabra reservada debe colocarse el nombre de la interfaz, por convención debe nombrarse con _Camel Case_. Las propiedades y métodos deben encerrarse entre llaves `{}` y en el caso de las propiedades debe especificarse los tipos de datos. A continuación un ejemplo: ``` interface User { name: string; lastname: string; email: string; age: number; married: boolean; } ``` La interfaz anterior se puede usar como tipo de dato de una variable: ``` let person: User; person = { name: "John", lastname: "Doe", email: "john.doe@mail.com", age: 30, married: false } ``` En caso de que algún dato definido en la interfaz no sea proporcionado en la asignación de la variable de tipo _User_, _typescript_ arrojará un error. Por ejemplo: ``` let person2: User; person2 = { name: "Mark", lastname: "Richards", age: 41, married: true } ``` En el ejemplo anterior, _typescript_ arrojaría un error al momento de compilar el código a _javascript_ ya que la propiedad _email_ no fue asignada en _person2_. ## Clases Al igual que en _Javascript_, en _Typescript_ es posible implementar una clase. Para ello, al igual que en _Javascript_ haremos uso de la palabra reservada _class_. Con _typescript_ podremos determinar el tipo de dato de las propiedades de la clase, así como el tipo de retorno en los métodos. Ejemplo: ``` class ShopCart { total: number; items: string[]; startDate: string; numberItems: number; constructor() { this.startDate = new Date(); } obtainTotal(): number { return this.items.reduce((total: number, sum; number)) => total + sum; } } ``` **Nota:** En el caso de las clases (_class_) y las interfaces (_interface_) es posible declarar una propiedad como opcional, esto se hace con la ayuda del símbolo `?` y se coloca delante del nombre de la propiedad opcional, pero antes de `:`. Ejemplo: ``` interface User { name: string; lastname: string; email: string; age?: number; married?: boolean; } ``` En el ejemplo anterior, las propiedades _age_ y _married_ son opcionales, por lo que, si se crea una instancia de la interfaz sin esos valores, _typescript_ lo permitiría sin arrojar ningún error. ``` let person: User; person = { name: "John", lastname: "Doe", email: "john.doe@mail.com" } ``` ## Compilar archivos typescript(.ts) Como mencionamos al principio de esta _wiki_, _typescript_ es solo un lenguaje de programación que se encargará de compilar el código y al final entregará un archivo de _javascript_. Para ello, debemos descargar el compilador para posteriormente utilizar el comando `tsc`. Para obtener la funcionalidad del comando de _ts compiler_ debemos instalar mediante _npm_: `npm install -g typescript` Una vez que tengamos instalado _typescript_, podemos compilar nuestro código mediante el comando: `tsc <nombreDelArchivo.ts>` Al ejecutar el comando anterior, obtendremos un archivo _js_ con el mismo nombre del archivo.