# Typescript (_TS_)

## 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.