John Cardozo
Software Engineer
John Cardozo
John Cardozo
TypeScript es un lenguaje de programación fuertemente tipado que genera código JavaScript, brindando mejores herramientas a cualquier escala.
transpile
Permite el uso de tipos
Alternativa a Javascript
Soporta características modernas
Características adicionales
interfaces
tuples
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
Instalación
Verificación
node --version
npm --version
Node Package Manager
Node
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
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
Variables, tipos, operadores
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
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 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
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
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
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
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
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
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
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, clase, propiedades, interfaces
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
}
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
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 |
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
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
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
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;
}
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;
}
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;
}
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
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
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
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
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
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
import, export
{
"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
Elementos, tipos
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
!
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
<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("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
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
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
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
johncardozo@gmail.com
By John Cardozo