FUNDAMENTOS DE TYPESCRIPT

John Cardozo

John Cardozo

FUNDAMENTOS DE TYPESCRIPT

qué es TYPEscript?

TypeScript es un lenguaje de programación fuertemente tipado que genera código  JavaScript, brindando mejores herramientas a cualquier escala.

transpile

TYPESCRIPT

Permite el uso de tipos

Alternativa a Javascript

Soporta características modernas

Características adicionales

interfaces

tuples

tipado estático vs tipado dinámico

TIPADO ESTÁTICO

TIPADO DINÁMICO

C++, C#, Java

Javascript, Python, Ruby

int numero = 10;
numero = "a";
let numero = 10;
numero = "a";
Math.round(numero);

Error en tiempo de desarrollo

Error en tiempo de ejecución

Typescript es Javascript con verificación de tipos

nodejs

Instalación

Verificación

node --version

npm --version

Node Package Manager

Node

instalación y ejecución de typescript

Instalación y verificación

npm install -g typescript

tsc --version

Versión

Instalación

Flag de instalación global

Ejecución

tsc app.ts

Convierte el archivo app.ts en el archivo app.js

Habilitar la ejecución de Scripts

Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned

Si hay problemas de ejecución se puede ejecutar el comando anterior

configuración del transpilador

let edad: number;
edad = 1;

Typescript

var edad;
edad = 1;

Javascript

Transpilación a versiones antiguas de Javascript

Genera var para la declaración de variables

tsc --init

Creación de archivo de configuración

{
  "compilerOptions": {
    "target": "es2016",
    "rootDir": "./src",
    "outDir": "./dist",
    "removeComments": true,
    "noEmitOnError": true
  },
  "include": ["./src"]
}

tsconfig.json

Valores básicos a activar

Configuración del transpilador

tsc

Ejecución del proyecto

tsc -w

Ejecución del proyecto cuando cambian los archivos fuente

fundamentos

fundamentos

Variables, tipos, operadores

variables

Declaración de variables

// Declaración de variable
let edad;

// Asignación de valor
// Tipo number
edad = 1;

// Error de tipo
edad = "e";

error de tipo

Type 'string' is not assignable to type 'number'

Verificación de tipos en tiempo de desarrollo

tipos de dato

Tipo implícito

// Declaración de variables
let nombre;
let edad;
let esAdulto;

// Asignación de valores
nombre = "Catalina";
edad = 21;
esAdulto = true;

Tipo explícito

// Declaración de variables
let nombre: string;
let edad: number;
let esAdulto: boolean;

// Asignación de valores
nombre = "Catalina";
edad = 21;
esAdulto = true;

Define el tipo de las variables dado el valor asignado

Define el tipo de las variables dado el tipo asignado

Javascript style

string

number

boolean

Tipos básicos de dato

let identificador: string | number;

Tipo Union

type alias

type StringOrNum = string | number

Creación de tipo

let variable: StringOrNum;

let arreglo: StringOrNum[];

let objeto: {
  propiedad: StringOrNum;
}

const funcion = (parametro: StringOrNum) => {
  console.log(parametro);
}

Uso del alias

type ObjectType = {nombre: string, dato: StringOrNum};

const funcion2 = (parametro: ObjectType) => {
  console.log(parametro.dato);
}

Creación y uso de un alias basado en otro alias

tipo any

let edad: any;

edad = 25;
edad = true;
edad = "Hello";

Cualquier tipo de dato

No es buena práctica

Javascript Style

let mezcla: any[] = [];

mezcla.push(10);
mexcla.push(true);
mezcla.push("Hola");

Arreglos: cualquier tipo de dato

let pelicula: {
  titulo: any,
  anio: any
}

pelicula = {
  titulo: 5,
  anio: "2023"
}

Objetos: cualquier tipo de dato

arreglos- I

Los tipos de datos de los arreglos deben coincidir

Error de tipo de argumento

Error de tipo de asignación

Se pueden tener varios tipos de datos

let heroes = ["superman", "batman", "aquaman"];
heroes.push(20);
heroes[0] = 10;
let notas = ["Catalina", 3.5, "Valeria", 4.5, "Luciana", 4.0];
notas.push(2);
notas[0] = 10;
notas.push(true);

Error de tipo de argumento

Se puede asignar cualquier valor permitido a cualquier posición

arreglos- ii

Declaración de arreglos con tipos explícitos

let juegos: string[] = [];
juegos.push("Super Mario");
juegos.push(3);

Error de tipo de argumento

Tipo de dato: string[]

Arreglos con tipo Union

let notas: (string | number)[] = [];
notas.push("Catalina");
notas.push(4.5);
notas.push(true);

Error de tipo de argumento

let juegos: string[];
juegos.push("Super Mario");

Sin valor de inicialización

Error de inicialización

tuples

let arreglo = ["Catalina", 21, true];

arreglo[0] = false;
arreglo[1] = "Maria";
arreglo[2] = 30;

Los arreglos permiten asignar cualquier tipo permitido en cualquier posición

let tup: [string, number, boolean] = ["cata", 25, true];

Las tuples permiten tipos en las posiciones específicas

let tup: [string, number, boolean] = [100, 25, true];

Errores de tipos

let tup: [string, number, boolean];
tup = ["Valeria", "10", true];
let tup: [string, number, boolean];
tup = ["Luciana", 3, false];
tup[0] = "Emilio"
tup[1] = true;

:

Se puede usar push después de la declaración si se cumple con cualquiera de los tipos de datos de la definición

ENUMS

enum TrainingType {
  TRAINING_RUN,
  INTERVALS,
  LONG_RUN,
}

Definición de Enum

let trainingType: TrainingType;

trainingType = TrainingType.LONG_RUN;

console.log(trainingType);

Uso de Enum

Definición de variable

Asignación de valor

Obtener valor

Imprime 2

Asigna 0, 1, 2 a cada valor del Enum

funciones - i

const areaCirculo = (radio: number): number => {
  return Math.pow(radio, 2) * Math.PI;
}

Parámetros y dato de retorno con tipo explícito

tipo de parámetro

tipo de retorno

Si el tipo de la función y el tipo de valor de retorno no coinciden se genera un error

let area1: number;

area1 = areaCirculo("3");

Error de tipo de argumento

let area2: string;

area2 = areaCirculo("3");

Error de tipo de asignación

Si la función no retorna ningún valor, el tipo debería ser  void

funciones - ii

const mensaje = (numero1: number, numero2: number | string) => {
  console.log(numero1 + numero2)
}

Parámetros tipo Union

Tipo Union

const mensaje = (numero1: number, numero2?: number | string) => {
  console.log(numero1);
  console.log(numero2);
}

Parámetros opcionales

Operador opcional

?

undefined

const mensaje = (parametro1: number = 10) => {
  console.log(parametro1);
}

Valores por default de parámetros

Valor por default

No requieren operador ?

Usualmente al final

let mensaje: (a: string, b: string) => void;

mensaje = (nombre: string, saludo: string) => {
  console.log(`${nombre} dice ${saludo}`);
}

mensaje("Catalina", "buenos días");

Definición y uso de signature

objetos

objetos

Objetos, clase, propiedades, interfaces

objetos - i

Definición de objeto con valores predeterminados

let pelicula = {
  titulo: "Django Unchained",
  anio: 2012
}

pelicula.titulo = "Pulp Fiction";
pelicula.titulo = 3;
pelicula.anio = "1990";

Error de tipo de asignación

pelicula = {
  titulo: "Inglorious Basterds",
  anio: 2009
}
pelicula = {
  titulo: "Kill Bill"
}

No hay error al asignar todas las propiedades

Error de propiedad faltante

pelicula = {
  titulo: "Kill Bill",
  anio: 2013,
  director: "Quentin Tarantino"
}

Error de propiedad desconocida

Error de propiedad faltante

Definición del objeto

let pelicula : {
  titulo: string,
  anio: number
}

clases y objetos

class Training {

  type: string;
  distance: number;
  date: string;
  comments: string;
  
  constructor(
    type: string,
    distance: number,
    date: string,
    comments: string = ""
  ) {
    this.type = type;
    this.distance = distance;
    this.date = date;
    this.comments = comments;
  }
  
  format() {
    return `On ${this.date}, 
            I ran ${this.distance}Kms 
            with ${this.type} technique. 
            ${this.comments}`;
  }
  
}

Definición de clases

const training1 = 
      new Training(
        "Intervals", 
        10, 
        "2023-03-02");

console.log(training1);

console.log(training1.format());

Creación de Objetos

let trainings: Training[] = [];
trainings.push(training1);
trainings.push(training2);

console.log(trainings);
trainings.forEach(
  (t) => console.log(t.format())
);

Arreglos de Objetos

Todas las propiedades son públicas por default

propiedades publicas, privadas y readonly

class Training {

  type: string;
  distance: number;
  date: string;
  public comments: string;
  
}

Propiedades públicas

public opcional, valor por default

class Training {

  type: string;
  distance: number;
  date: string;
  private comments: string;
  
}

Propiedades privadas

private

const training = 
      new Training(
        "Intervals", 
        10, 
        "2023-03-02",
        "Great training");

console.log(training.distance);

La propiedad es privada y sólo es accesible dentro de la clase

class Training {

  type: string;
  readonly distance: number;
  date: string;
  comments: string;
  
}

Propiedades sólo lectura

readonly

console.log(training1.distance);
training1.distance = 20;

No se puede asignar un valor porque la propiedad es de sólo lectura

lectura escritura
public interno
externo
interno
externo
private interno
externo
interno
externo
readonly interno
externo
interno
externo

constructor: propiedades publicas, privadas y readonly

class Training {
  
  type: string;
  distance: number;
  date: string;
  comments: string;
  
  constructor(
    type: string,
    distance: number,
    date: string,
    comments: string = ""
  ) {
    this.type = type;
    this.distance = distance;
    this.date = date;
    this.comments = comments;
  }
  
}

Constructor con propiedades explícitas

Los parámetros del constructor deben tener las palabras public, private o readonly

class Training {
  
  constructor(
    public type: string,
    readonly distance: number,
    public date: string,
    private comments: string = ""
  ) { }
  
}

Constructor con propiedades implícitas

encapsulamiento: getters / setters

class Training {
  constructor(
    public type: string,
    readonly distance: number,
    public date: string,
    private comments: string = ""
  ) { }
  
  public set comments(comments: string) {
    this._comments = comments;
  }

  public get comments(): string {
    return this._comments;
  }
}

setter

getter

Encapsulamiento

propiedad privada

Únicamente se puede acceder a través del getter/setter

constructor

herencia

class Person {
  constructor(private firstName: string, private lastName: string) {}
  public getFullName(): string {
    return `${this.firstName} ${this.lastName}`;
  }
}

Clase Person
Padre

class Teacher extends Person {
  constructor(firstName: string, lastName: string, private code: string) {
    super(firstName, lastName);
    this.code = code;
  }
}

Clase Teacher
Hija

class Student extends Person {
  constructor(firstName: string, lastName: string, private avg: number) {
    super(firstName, lastName);
    this.avg = avg;
  }
}

Clase Student
Hija

const teacher1: Person = new Teacher("John", "Cardozo", "007");
const teacher2: Person = new Teacher("German", "Macias", "008");
console.log(teacher1.getFullName());
console.log(teacher2.getFullName());

const student1: Person = new Student("Catalina", "Giraldo", 4.5);
const student2: Person = new Student("Valeria", "Medina", 4.7);
console.log(student1.getFullName());
console.log(student2.getFullName());

Use de las clases hijas

Las interfaces no generan objetos

Una interface es una estructura que define un contrato  en la aplicación

interfaces

Una interface define la sintaxis que deben seguir las clases

Las clases que implementen una interface deben seguir la estructura definida por la interface

Las interfaces definen clases

Una interface no tiene constructor

interface ITraining {
  type: string;
  distance: number;
  date: string;
  comments: string;
  format(s: string): string;
}

polimorfismo: interfaces

Definición de interface

const training: ITraining = {
  type: "",
  distance: 0,
  date: "203",
  comments: "",
  format(system: string): string {
    if (system === "imperial") {
      return `${this.distance} miles`;
    } else {
      return `${this.distance} kms`;
    }
  },
};

Uso de la interface

El objeto debe cumplir con todas las características de la interface

El objeto no puede tener características adicionales

interface ITraining {
  format(): string;
}

uso de interfaces y clases

Definición de interface

export class Training implements ITraining {
  constructor(
    public type: string,
    readonly distance: number,
    public date: string,
    private comments: string = ""
  ) {}

  format() {
    return `On ${this.date}, 
            I ran ${this.distance}Kms 
            with ${this.type} technique. 
            ${this.comments}`;
  }
}

Definición de clase implementando la interface

implements obliga que la clase tenga la estructura de la interface

Si la clase no imlementa la función format se genera un error

Una clase puede implementar varias interfaces

interface ITraining {
  type: string;
  distance: number;
  date: string;
  comments: string;
  formatDistance(s: string): string;
}

interfaces como parámetros de funciones

Definición de interface

const showTrainingType = (training: ITraining) => {
  console.log(training.type);
}

Interface como parámetro

La interface asegura que el objeto cuenta con la propiedad

Interface como propiedad

showTrainingType(
  {date: "2023-04-23", type: "Long run"}
);

Error al usar la función

El objeto no tiene la estructura de la interface

clases implementando interfaces - I

export interface ITraining {
  type: string;
  distance: number;
  date: string;
  comments: string;
  format(): string;
  getLabelClass(): string;
}
 class Intervals implements ITraining {
  readonly type: string;
  sections: number[];
  constructor(
    readonly distance: number,
    public date: string,
    public comments: string = ""
  ) {
    this.type = "Intervals";
    this.sections = [];
  }
  getLabelClass(): string {
    return "intervals";
  }

  format() {
    const values = this.sections.join();
    return `This intervals session
            was on ${this.date} with a 
            distance of ${this.distance} 
            Kms. These were the values
            ${values}
            Comments: ${this.comments}`;
  }
}

Interface ITraining

Clase Intervals

clases implementando interfaces - II

class LongRun implements ITraining {
  readonly type: string;
  kcalories: number;
  constructor(
    readonly distance: number,
    public date: string,
    public comments: string = ""
  ) {
    this.type = "Long run";
    this.kcalories = 0;
  }
  format() {
    return `This long run was on 
            ${this.date} 
            with a distance of 
            ${this.distance}Kms and 
            ${this.kcalories} burnt
            Comments: ${this.comments}`;
  }
  getLabelClass(): string {
    return "long-run";
  }  
}

Clase LongRun

class TrainingRun implements ITraining {
  readonly type: string;
  constructor(
    readonly distance: number,
    public date: string,
    public comments: string = ""
  ) {
    this.type = "Training run";
  }

  format() {
    return `This training run was on 
           ${this.date} with a distance 
           of ${this.distance}Kms.
           Comments: ${this.comments}`;
  }
  getLabelClass(): string {
    return "training-run";
  }
}

Clase TrainingRun

uso de clases implementando interfaces

let trainings: ITraining[] = [];
let training1: ITraining;
let training2: ITraining;
let training3: ITraining;

Declaración de variables usando la interface

training1 = new TrainingRun(5, "2023-04-23");
training2 = new Intervals(10, "2023-04-24");
training3 = new LongRun(21, "2023-04-25");
trainings.push(training1);
trainings.push(training2);
trainings.push(training3);

Creación de objetos que implementan la interface

trainings.forEach((training) => console.log(training.format()));

Los objetos agregados al arreglo que implementa la interface

Se invoca el método format en cada objeto dado que todos implementan la interface ITraining

generics- I

interface IMovie {
  id: number;
  title: string;
  actors: string[];
}

Definición de interface sin generics

const movie1: IMovie = {
  id: 1,
  title: "pf",
  actors: ["john"],
};
const movie2: IMovie = {
  id: 1,
  title: "pf",
  actors: [
    { firstName: "john", lastName: "Travolta" },
    { firstName: "Uma", lastName: "Thurman" },
  ],
};

Error

generics- II

interface IMovie<T> {
  id: number;
  title: string;
  actors: T;
}

Definición de interface con generics

const movieA: IMovie<string[]> = {
  id: 1,
  title: "pf",
  actors: ["john"],
};
const movieB: IMovie<object[]> = {
  id: 1,
  title: "pf",
  actors: [
    { firstName: "john", lastName: "Travolta" },
    { firstName: "Uma", lastName: "Thurman" },
  ],
};

Definición de tipo dinámico

Match de tipos de dato

módulos

módulos

import, export

módulos

{
  "target": "es2016",
  "module": "ES6"
}

tsconfig.json

<script src="app.js" type="module">
</script>

HTML

activación de módulos

export class Training {
  constructor(
    public type: string,
    readonly distance: number,
    public date: string,
    private comments: string = ""
  ) {
      
    }
}

training.ts

import { Training } from "./training.js";

const training1 = 
      new Training(
        "Intervals", 
        10, 
        "2023-03-02");

console.log(training1);

app.ts

Configuración para uso de módulos

Uso de módulos

export

import

Se debe importar con extensión .js

dom

dom

Elementos, tipos

DOM + type casting - I

const anchor = document.querySelector("a");
console.log(anchor);
console.log(anchor.href);

Obtener elemento - JS Style

Posiblemente null

Posibles soluciones

const anchor = document.querySelector("a");
if(anchor) {
  console.log(anchor.href);
}

Verificación de valor

const anchor = document.querySelector("a")!;
console.log(anchor.href);

Asegurar que el valor existe

!

DOM + type casting - II

const anchor = document.querySelector("a")!;
console.log(anchor.href);

Selector por tag

const anchor = document.querySelector(".clase")!;
console.log(anchor.href);

Selector por clase

HTMLAnchorElement

Element

Brinda propiedades específicas del anchor

Brinda propiedades genéricas

const anchor = document.querySelector(".clase") as HTMLAnchorElement;
console.log(anchor.href);

Casting

No necesita el operador ! porque el cast asegura que habrá un valor

Obteniendo elementos dom

<form autocomplete="off">
  <fieldset>
    <label for="type">Type</label>
    <select id="type">
      <option value="1">Training run</option>
      <option value="2">Intervals</option>
      <option value="3">Long run</option>
    </select>
  </fieldset>
  <fieldset>
    <label for="date">Date</label><input type="date" id="date" />
  </fieldset>
  <fieldset>
    <label for="distance">Distance</label><input type="number" id="distance" />
  </fieldset>
  <fieldset>
    <label for="comments">Comments</label><input type="text" id="comments" />
  </fieldset>
  <fieldset>
    <button>Add</button>
  </fieldset>
</form>

HTML

const form = document.querySelector("form")!;
const type = document.querySelector("#type") as HTMLSelectElement;
const date = document.querySelector("#date") as HTMLInputElement;
const distance = document.querySelector("#distance") as HTMLInputElement;
const comments = document.querySelector("#comments") as HTMLInputElement;

TypeScript

!

form addeventlistener

form.addEventListener("submit", (event: Event) => {
  // Prevent sending the form
  event.preventDefault();

  // Shows the values
  console.log(type.value);
  console.log(date.value);
  console.log(distance.valueAsNumber);
  console.log(comments.value);
});

evento de tipo Event

Tipo Event

valueAsNumber convierte el valor digitado en el input[type=number] en valor number

Si se usa value, obtiene un string

creando objetos dados los datos del usuario

const TRAINING_RUN = 1;
const INTERVALS = 2;
const LONG_RUN = 3;

// Get form elements
// ...
// 
form.addEventListener("submit", (event: Event) => {
  // Prevent sending the form
  event.preventDefault();

  let training: ITraining;
  const typeValue = parseInt(type.value);

  if (typeValue === TRAINING_RUN) {
    training = new TrainingRun(
      distance.valueAsNumber,
      date.value,
      comments.value
    );
  } else if (typeValue === INTERVALS) {
    training = new Intervals(
      distance.valueAsNumber,
      date.value,
      comments.value
    );
  } else if (typeValue === LONG_RUN) {
    training = new LongRun(
      distance.valueAsNumber, 
      date.value, 
      comments.value);
  }
  console.log(training!.format());
});

Definición de constantes

Interface

Creación de un objeto dependiendo de la selección del usuario

Invoca la función format

Obtiene la selección del usuario

agregar y mostrar los datos - i

export let trainings: ITraining[] = [];

data.ts

// Model...
// UI
import { TrainingList } from "./ui/trainingList.js";
// Data
import { trainings } from "./data/data.js";

// Get form elements...

// Create
const trainingList = new TrainingList(tbody);

form.addEventListener("submit", (event: Event) => {
  // Prevent sending the form
  event.preventDefault();

  // Create the object...
  let training: ITraining;

  // Add the new training
  trainings.unshift(training!);

  // Render the list
  trainingList.render(trainings);
});

app.ts

agregar y mostrar los datos - iI

import { ITraining } from "../interfaces/ITraining";

export class TrainingList {
  constructor(private container: HTMLTableSectionElement) {}
  render(trainings: ITraining[]) {
    this.container.innerHTML = "";
    trainings.forEach((training) => {
      const tr = document.createElement("tr");
      const dateTd = document.createElement("td");
      dateTd.textContent = training.date;
      const typeTd = document.createElement("td");
      const spanType = document.createElement("span");
      spanType.classList.add(training.getLabelClass());
      spanType.textContent = training.type;
      typeTd.appendChild(spanType);
      const distanceTd = document.createElement("td");
      distanceTd.textContent = `${training.distance}k`;
      const commentTd = document.createElement("td");
      commentTd.textContent = training.comments;
      const removeTd = document.createElement("td");
      const removeDiv = document.createElement("div");
      removeDiv.classList.add("trash");
      removeTd.appendChild(removeDiv);
      tr.append(dateTd, typeTd, distanceTd, commentTd, removeTd);
      this.container.prepend(tr);
    });
  }
}

trainingList.ts

Limpia el contenedor

Constructor referenciando el contenedor

Recorre la lista de objetos

Agrega el elemento creado al contenedor

Crea un elemento HTML dados los datos del objeto

john cardozo

johncardozo@gmail.com

Typescript: Fundamentos

By John Cardozo

Typescript: Fundamentos

  • 145