Skip to content

TypeScript

[Guia Oficial para Instalar Node JS con WSL]

El paquete Node JS, incluye una línea de comandosprograma llamado Node Package Manager ( npm ), para descargar y poner a disposición una gran cantidad de bibliotecas de tiempo de ejecución, de las cuales TypeScript es una. Estos paquetes se pueden instalar globalmente y, por lo tanto, se pueden usar en todo el sistema, o se pueden instalar localmente. Los paquetes de Node instalados localmente se instalarán dentro de un subdirectorio llamado , y los paquetes de Node instalados globalmente se instalarán en el directorio de todo el sistema. Para verificar que npm se haya instalado correctamente, escriba lo siguiente en el símbolo del sistema:

Sino está instalado, Dirigirse a la documentación de esta guía:

Instalar Node.js en Windows Subsystem para Linux (WSL2)

Seguidamente, verifique en el símbolo del sistema:

npm --version

Luego, se procede instalar el compilador de TypeScript globalmente, escriba lo siguiente en su símbolo del sistema:

npm install -g typescript

Aquí, estamos instalando el paquete Node globalmente, usando la opción. Aunque el paquete de Node tiene nombre , hace que un ejecutable de Node esté disponible llamado que invocará el compilador de TypeScript. Para verificar que TypeScript se haya instalado correctamente, escriba lo siguiente en el símbolo del sistema:

tsc --version

Aquí estamos invocando el compilador de línea de comandos de TypeScript ( ) y usando el argumento para informar la versión actual del compilador.

Realizamos nuestro primer ejemplo:

Crear una carpeta y dentro de el un archivo .ts

01_Ejemplo.ts

console.log("Hola Uniguajira");

Acto seguido,

tsc 01_Ejemplo.ts

En ese momento se crea otro archivo con el mismo nombre, pero como extensión .js, que para este caso sería 01_Ejemplo.js

Si queremos ejecutar este primer programa debemos ejecutar el archivo .js de la siguiente manera:

node 01_Ejemplo.js

Para este caso se obtiene el siguiente resultado:

Hola Uniguajira

Interpolación Mostrar Información

Puedo interpolar cadenas con variables de la siguiente manera:

En el mismo archivo, agregar las siguientes líneas.

console.log("Hola Uniguajira");

let nombre = "Jaider Quintero"
console.log(`Hola ${nombre}, Bienvenido a Uniguajira`);

Utilizo el símbolo Comillas invertida, para interpolar cadenas con variables.

Si nuevamente ejecutamos,

tsc 01_Ejemplo.ts

node 01_Ejemplo.js

Obtenemos como resultado:

Hola Uniguajira
Hola Jaider Quintero, Bienvenido a Uniguajira

Configuración del proyecto TypeScript

Para ello creamos una nueva carpeta, y en la consola digitamos

tsc --init

Esta opción generará automáticamente un archivo dentro del directorio actual, que se utiliza, entre otras cosas, para especificar la versión de JavaScript de destino. Echemos un vistazo rápido a este archivo tsconfig.json

{
  "compilerOptions": {
    /* Visit https://aka.ms/tsconfig.json to read more about this file */

    /* Basic Options */
    // "incremental": true,                         /* Enable incremental compilation */
    "target": "es5",                                /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */
    "module": "commonjs",                           /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
    // "lib": [],                                   /* Specify library files to be included in the compilation. */
    // "allowJs": true,                             /* Allow javascript files to be compiled. */
    // "checkJs": true,                             /* Report errors in .js files. */
    // "jsx": "preserve",                           /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
    // "declaration": true,                         /* Generates corresponding '.d.ts' file. */
    // "declarationMap": true,                      /* Generates a sourcemap for each corresponding '.d.ts' file. */
    // "sourceMap": true,                           /* Generates corresponding '.map' file. */
    // "outFile": "./",                             /* Concatenate and emit output to single file. */
    // "outDir": "./",                              /* Redirect output structure to the directory. */
    // "rootDir": "./",                             /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
    // "composite": true,                           /* Enable project compilation */
    // "tsBuildInfoFile": "./",                     /* Specify file to store incremental compilation information */
    // "removeComments": true,                      /* Do not emit comments to output. */
    // "noEmit": true,                              /* Do not emit outputs. */
    // "importHelpers": true,                       /* Import emit helpers from 'tslib'. */
    // "downlevelIteration": true,                  /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
    // "isolatedModules": true,                     /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */

    /* Strict Type-Checking Options */
    "strict": true,                                 /* Enable all strict type-checking options. */
    // "noImplicitAny": true,                       /* Raise error on expressions and declarations with an implied 'any' type. */
    // "strictNullChecks": true,                    /* Enable strict null checks. */
    // "strictFunctionTypes": true,                 /* Enable strict checking of function types. */
    // "strictBindCallApply": true,                 /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
    // "strictPropertyInitialization": true,        /* Enable strict checking of property initialization in classes. */
    // "noImplicitThis": true,                      /* Raise error on 'this' expressions with an implied 'any' type. */
    // "alwaysStrict": true,                        /* Parse in strict mode and emit "use strict" for each source file. */

    /* Additional Checks */
    // "noUnusedLocals": true,                      /* Report errors on unused locals. */
    // "noUnusedParameters": true,                  /* Report errors on unused parameters. */
    // "noImplicitReturns": true,                   /* Report error when not all code paths in function return a value. */
    // "noFallthroughCasesInSwitch": true,          /* Report errors for fallthrough cases in switch statement. */
    // "noUncheckedIndexedAccess": true,            /* Include 'undefined' in index signature results */
    // "noImplicitOverride": true,                  /* Ensure overriding members in derived classes are marked with an 'override' modifier. */
    // "noPropertyAccessFromIndexSignature": true,  /* Require undeclared properties from index signatures to use element accesses. */

    /* Module Resolution Options */
    // "moduleResolution": "node",                  /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
    // "baseUrl": "./",                             /* Base directory to resolve non-absolute module names. */
    // "paths": {},                                 /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
    // "rootDirs": [],                              /* List of root folders whose combined content represents the structure of the project at runtime. */
    // "typeRoots": [],                             /* List of folders to include type definitions from. */
    // "types": [],                                 /* Type declaration files to be included in compilation. */
    // "allowSyntheticDefaultImports": true,        /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
    "esModuleInterop": true,                        /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
    // "preserveSymlinks": true,                    /* Do not resolve the real path of symlinks. */
    // "allowUmdGlobalAccess": true,                /* Allow accessing UMD globals from modules. */

    /* Source Map Options */
    // "sourceRoot": "",                            /* Specify the location where debugger should locate TypeScript files instead of source locations. */
    // "mapRoot": "",                               /* Specify the location where debugger should locate map files instead of generated locations. */
    // "inlineSourceMap": true,                     /* Emit a single file with source maps instead of having a separate file. */
    // "inlineSources": true,                       /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */

    /* Experimental Options */
    // "experimentalDecorators": true,              /* Enables experimental support for ES7 decorators. */
    // "emitDecoratorMetadata": true,               /* Enables experimental support for emitting type metadata for decorators. */

    /* Advanced Options */
    "skipLibCheck": true,                           /* Skip type checking of declaration files. */
    "forceConsistentCasingInFileNames": true        /* Disallow inconsistently-cased references to the same file. */
  }
}

Aquí, podemos ver que el archivo utiliza la sintaxis JSON estándar para especificar un objeto que tiene una propiedad principal, denominada , y dentro de esta propiedad principal, una serie de sub propiedades .

Ahora, cambiemos los siguientes valores:

"target": "es6"

"outFile": "./js/app.js"

"outDir": "./js"

"rootDir": "./src"

Para que esto funcione correctamente solo debe crear un archivo dentro de la sub carpeta de nombre src\app.ts,

console.log("Hola Uniguajira");

let nombre = "Jaider Quintero"
console.log(`Hola ${nombre}, Bienvenido a Uniguajira`);

y para compilar utilice:

tsc

Con este comando genera todos los archivos y carpetas de los archivos .js, en las carpetas indicadas.

Si se encuentra ubicado en la carpeta raíz 02_Ejemplo, puede ejecutar el archivo de la siguiente forma:

node js/app.js

Observación de archivos en busca de cambios

En ocasiones resulta dificil, que cada vez que modifiquemos algo en el archivo .ts, debemos generar el javascript, por consiguiente nos vemos obligatoriamente ejectar demasiadas veces tsc.

Por consiguiente, TypeScript también tiene una opción útil que observará un árbol de directorios completo, y si un archivo cambia, recompilará automáticamente todo el proyecto. Ejecutemos el compilador de TypeScript en este modo de la siguiente manera:

tsc -w

De esta manera podemos modificar el archivo src\app.tsque se genera el javascript automáticamente.

Escritura fuerte

La escritura fuerte, o escritura estática como también se le conoce, significa que cuando creamos una variable, o definimos un parámetro en una función, especificamos de qué tipo se trata.

Esto contradice lo realizado por javascript, quien no define los tipos de variables. Una vez especificado este tipo, no podemos cambiarlo.

Veamos el siguiente ejemplo:

var nombre = "Jaider Quintero" // Asigno una cadena a la variable nombre
nombre = 47 //Asigno un numero a la variable nombre

Si tenemos activo la compilación con tsc -w, puede observar que no existen errores de compilación, pero TypeScript nos avisa que existe un error de sintaxis. si colocamos el cursor encima de la asignación nombre = 47, aparece el error Type 'number' is not assignable to type 'string'.ts(2322).

En conclusión hemos iniciado con una variable de tipo cadena y luego asignamos un valor numérico, presentando el error de sintaxis, es decir TypeScript, es fuertemente tipado, por eso indica el error, mientras javascript admite este tipo de asignaciones sin presentar errores al respecto.

Tipos básicos

TypeScript proporciona una serie de tipos básicos que se pueden utilizar para la anotación de tipos. Como ejemplo de estos tipos, centrémonos en cuatro tipos comunes, a saber, cadena, número, booleano y matriz. Cubriremos el resto de estos tipos básicos, como cualquiera, null, nunca y otros, en un capítulo posterior, pero por ahora, usemos estos cuatro tipos básicos de la siguiente manera:

var myBoolean : boolean = true;
var myNumber : number = 1234;
var myStringArray : string[] = ['Juan', 'Pedro', 'Lucas'];

console.log(myBoolean)          // Muestra el contenido de la variable myBoolean
console.log(typeof(myBoolean))  // Muestra el tipo de la variable myBoolean

console.log(myNumber)           // Muestra el contenido de la variable myNumber
console.log(typeof(myNumber))   // Muestra el tipo de la variable myNumber

console.log(myStringArray)          // Muestra el contenido de la variable myStringArray
console.log(typeof(myStringArray))  // Muestra el tipo de la variable myStringArray

Muestra el siguiente resultado:

true
boolean
1234
number
['Juan', 'Pedro', 'Lucas']
object

Escritura inferida

TypeScript también utiliza una técnica denominada escritura inferida, o inferencia de tipos, para determinar el tipo de una variable. Esto significa que incluso si no especificamos explícitamente el tipo de una variable, el compilador determinará su tipo en función de cuándo se asignó por primera vez. Una vez más, una vez que la variable tiene un tipo, se utilizarán comparaciones de tipos normales. Para ello utilizaremos el mismo ejemplo anterior:

var myBoolean = true;
var myNumber = 1234;
var myStringArray = ['Juan', 'Pedro', 'Lucas'];

console.log(myBoolean)          // Muestra el contenido de la variable myBoolean
console.log(typeof(myBoolean))  // Muestra el tipo de la variable myBoolean

console.log(myNumber)           // Muestra el contenido de la variable myNumber
console.log(typeof(myNumber))   // Muestra el tipo de la variable myNumber

console.log(myStringArray)          // Muestra el contenido de la variable myStringArray
console.log(typeof(myStringArray))  // Muestra el tipo de la variable myStringArray

Omitimos la asignación del tipo de cada variable y el infiere y detecta el tipo mediante los tipos de los valores que le son asignados.

Si ubicamos encima del nombre de cada variable, nos indica visualmente el tipo.

Escritura de pato

TypeScript también utiliza un método llamado duck typing para tipos de variables más complejas. La escritura de pato sugiere que "si parece un pato, y grazna como un pato, entonces probablemente sea un pato". En otras palabras, se considera que dos variables tienen el mismo tipo si tienen las mismas propiedades y métodos. Probemos esta teoría con el siguiente código:

let persona = {
    nombre: 'Jaider Quintero',
    Cargo: 'Docente',
    Salario: 1500000,

}

persona = {
    nombre: 'Sandy Romero',
    Cargo: 'Docente',
    Salario: 3500000,
    sexo: 'Femenino',
}

Al momento de definir persona, tiene unas propiedades y valores, pero en la segunda asignación, aparece un error porque el compilador TypeScript espera que cualquier asignación posterior a la definición tenga el mismo comportamiento y en cuanto a las propiedades del objeto.

Posteriormente se explica como puede definirse que alguna de sus propiedades no sean obligatorias.

Firmas de función y anulación

Hasta ahora, hemos tenido un recorrido rápido por los conceptos básicos del lenguaje TypeScript, cómo introduce anotaciones de tipo para variables y cómo utiliza la escritura inferida y la escritura de pato para verificar asignaciones válidas. Una de las mejores características de usar anotaciones de tipo en TypeScript es que también se pueden usar para escribir fuertemente firmas de funciones.

Ejemplaricemos esta definición.

function calcularDatos(a, b, c) {
    return (a * b) + c
}

console.log("calcularDatos() = " + calcularDatos(8, 7, 5));

Resultado del programa

calcularDatos() = 61

Se puede observar que la función calcularDatos(8, 7, 5), envía los argumentos, los números 8, 7, y 5 respectivamente, los cuales son recibidos respectivamente en las variables a, b y c.

Obviamente a pesar que no especificamos los tipos de datos a enviar, el asume que son numéricos, porque efectivamente le está enviando tres números.

Pero si cambiamos la ultima linea del programa por:

console.log("calcularDatos() = " + calcularDatos("8", "7", "5"));

quedando de la siguiente manera:

function calcularDatos(a, b, c) {
    return (a * b) + c
}

console.log("calcularDatos() = " + calcularDatos("8", "7", "5"));

Obtenemos como resultado:

calcularDatos() = 565

Expliquemos esto:

Ahora ya no enviamos números sino que enviamos texto o cadenas: "8", "7", "5", el cual nuestro compilador TypeScript traduce de la siguiente manera:

(a * b), quienes reciben "8" y "7", respectivamente. En este caso el compilador a pesar de recibir texto los multiplica como si se tratase de números. es decir nos daría 56.

A ese valor de 56, se le suma el valor de c que es igual "5". Pero en este caso la suma de texto, el traductor no los trata como números, sino como cadenas, es decir que le concatena ese numero.

Quedando como resultado 56 + 5 = 565.

En conclusión, al no indicar los parámetros en la función los tipos de variables que recibe, el infiere de acuerdo al tipo de variable que le llega de la llamada a la función.

Si se envía texto o cadena, los recibe como cadenas y si les envían números, los recibe como números.

Cambiemos el panorama, indicando los tipos de variables en los parámetros de la función.

function calcularDatos(a: number, b: number, c: number) : number{
    return (a * b) + c
}

console.log("calcularDatos() = " + calcularDatos(8, 7, 5));

Obtenemos como resultado:

calcularDatos() = 565

Tanto los valores que recibe, como el valor que devuelve se denotan como numéricos, es decir que si en el llamado a la función se le envían textos o cadenas, genera un error automáticamente.

Probar el código siguiente y comprobar dicho error.

function calcularDatos(a: number, b: number, c: number) : number{
    return (a * b) + c
}

console.log("calcularDatos() = " + calcularDatos("8", "7", "5"));

El traductor de TypeScript, nos indica el error en el llamado a la función, justo en el primer argumento, es decir, "8". Si se cambia el "8", texto en números, vuelve y pasa el error en siguiente argumento "7" y si seguimos corrigiendo, lo sigue pasando al siguiente argumento y así sucesivamente.

Depuración de VS Code

Para depurar el programa en TypeScript en Visual Studio Code, descomentar la linea "sourceMap": true, del archivo tsconfig.json

Para realizar el Dubug del programa, para ejecutar línea por línea:

Primero seleccione con un punto rojo, la linea hasta donde desea realizar la primera ruptura del programa.

Luego una vez terminado el programa, RUN en el menú de opciones >> Start Debugging

O simplemente la tecla F5.

Tipo de Variable Any

let ciudad: any = "Riohacha";
console.log(ciudad);

ciudad = 455
console.log(ciudad);

ciudad = true
console.log(ciudad);

Se obtiene como resultado:

Riohacha
455
true

Observamos que la variable ciudad, acepta cualquier tipo de valor.

Uso y Ámbito de las Variables

Hay cuatro formas de declarar una variable. Están

  • tanto el tipo como el valor inicial

  • sin tipo, pero con un valor inicial

  • solo el tipo

  • Sin Tipo/Valor Inicial

Declaraciones con Let, Var y Const

Uso de Var

Las variables declaradas usando vardentro de la función están disponibles solo dentro de esa función. Si los declaramos fuera de la función, entonces están disponibles en todas partes, es decir, son una variable global.

Si los definimos dentro de un bloque de código, todavía están dentro del alcance de la función envolvente, ademas se pueden actualizar o re-definir.

Se puede acceder a la variable, incluso antes de que las declaremos. Esto se llama elevación variable.

Uso de let y const

Las variables declaradas usando leto consttienen un alcance de bloque. Están en el ámbito del bloque en el que se declaran, es decir, dentro de if/try/catch/while/for o cualquier bloque de código (entre paréntesis).

Esto significa que solo podemos usarlo en el bloque de código donde los declaramos. Fuera del bloque de código, son invisibles.

Si están fuera del bloque de código, pero dentro del cuerpo de la función, se vuelven de ámbito de función.

Si están fuera del bloque de función y código, entonces están disponibles globalmente o se convierten en una variable global.

Tipos de unión

TypeScript nos permite expresar un tipo como uncombinación de dos o más de otros tipos. Estos tipos se conocen como tipos de unión y utilizan el símbolo de barra vertical ( ) para enumerar todos los tipos que conformarán este nuevo tipo. Considere el siguiente código:|

/*  Tipos de Union   */
let edad: number | string
edad = 40
console.log(edad)

edad = '47 años'
console.log(edad)

Tipo guardias

Al trabajar con tipos de unión, elel compilador seguirá aplicando sus sólidas reglas de escritura para garantizar la seguridad de los tipos. Como ejemplo de esto, considere el siguiente código:

let var1: number | string;
let var2: number | string;
var1 = 20;
var2 = 27
let total1 = var1 + var2;
console.log(total1)

var1 = 'hola';
var2 = 'typescript'
let total2 = var1 + var2;
console.log(total2)

Para ambos casos, en la situación de var1 y var2, para cuando contienen valores de cadenas o numéricos.

Tipo de alias

TypeScript introduce el concepto de unalias de tipo, donde podemos crear un tipo con nombre que se puede usar como sustituto de una unión de tipos. Los alias de tipo se pueden usar siempre que se usen tipos normales y se indican mediante la palabra clave, de la siguiente manera:

type CarAnyo = number
type CarTipo = string
type CarModelo = string
type Carro = {
  anyo: CarAnyo,
  tipo: CarTipo,
  modelo: CarModelo
}

const carAnyo: CarAnyo = 2001
const carTipo: CarTipo = "Toyota"
const carModelo: CarModelo = "Corolla"
const carro: Carro = {
  anyo: carAnyo,
  tipo: carTipo,
  modelo: carModelo
};

Enumeraciones constantes

Permiten definir un conjunto de constantes con nombre, y se realizan de la siguiente manera:

/*  Enum   */

enum Docente {
  Planta = 'Planta',
  Catedratico = 'Catedratico',
  Ocasional = 'Ocasional'
}

let contDocente = Docente.Planta;
console.log(contDocente)

Indefinido y Valores opcionales

undefinedSe presenta cuando se declara una variable pero no se le asignó un valor, entonces no está definida.

Valores Opcionales: ? Se denota cuando un parámetro es opcional que se envíe o no.

Veamos el siguiente ejemplo:

function calcularSuma(a: number, b: number, c?: number) {
  let s:number
  if (c==undefined) {
    s =  a + b
  }
  else s = a+b+c
  return s
}

console.log(calcularSuma(3,4))  // Enviando solo dos parámetros - a y b
console.log(calcularSuma(3,4,5))  // Enviando tres parámetros - a, b y c

Valores Nulos

Establece valores en null. Establecer un valor para nullpretende indicar que la variable es conocida, pero no tiene valor, a diferencia de indefinido, donde la variable no se ha definido en el ámbito actual. Considere el siguiente código:

function calcularSuma(a: number, b: number, c: number | null) {
  let s:number
  if (c==null) {
    s =  a + b
  }
  else s = a+b+c
  return s
}

console.log(calcularSuma(3,4,null))  // Enviando solo dos parámetros - a y b
console.log(calcularSuma(3,4,5))  // Enviando tres parámetros - a, b y c

Expresiones condicionales

Es una versión simplificada y optimizada de la declaración if, else, que usa un signo de interrogación ( ?). El formato de una expresión condicional es el siguiente:

Sintaxis:

(conditional) ? ( true statement )  :  ( false statement );

Como ejemplo de esta sintaxis, considere el siguiente código:

/*
  Expresión Condicional
*/

let salario: number = 980000

let calSeguridadSocial: string = (salario <= 1000000 ? "No paga seg social": "se le descuenta seg social");
console.log(calSeguridadSocial)

Objetos y Propiedades

Los tienen la siguiente estructura de clave y valor.

let estructuraObjeto = {
  'name': "Mi Nuevo Objeto",
  'propiedades': {
      id: 1,
      tipo: "Clase de Objeto"
  }
}

console.log(estructuraObjeto.propiedades.tipo)
console.log(JSON.stringify(estructuraObjeto))
console.log(estructuraObjeto)

Objetos, Propiedades Anidadas y Listas

Las propiedades anidadas tienen la siguiente estructura:

let ventasPelicula = {
  "fechaVenta":"2021-05-05",
  "pricioTotal":"345",
  "cliente":
        {
          nombre: "Jaider Quintero",
          cedula: "84035444"
        },
  "pelicula": [
      {
          "nombre": "No retroceder, no rendirse jamas",
          "precio": 29000,
          "coleccion": 2018

      },

      {
        "nombre": "Duro de matar",
        "precio": 180000,
        "coleccion": 2010

      },

  ]
}

console.log(ventasPelicula.fechaVenta)
console.log(ventasPelicula.cliente.nombre)
console.log(ventasPelicula.pelicula[0].nombre)