Typescript

Introducción

Typescript es un superset de Javascript, lo cual no significa que agrega nuevas funcionalidades al lenguaje de programación, más bien ayuda a escribir de una mejor manera el código Javascript mediante type safety y así evitando problemas en el momento de ejecución. Como lo hace es analizando el código estático previo a ser ejecutado.

Aquí hay algunos propósitos y beneficios clave de usar TypeScript:

  1. Tipado Estático:

    • Detección temprana de errores: TypeScript permite detectar errores en tiempo de desarrollo en lugar de en tiempo de ejecución, lo que ayuda a evitar errores comunes y a mejorar la estabilidad del código.

    • Autocompletado y documentación: Los editores de código y los entornos de desarrollo integrados (IDE) pueden proporcionar autocompletado, documentación en línea y comprobaciones de tipos gracias a la información de tipos disponible.

  2. Mejor Mantenimiento del Código:

    • Refactorización segura: Las herramientas de refactorización pueden ser más efectivas y seguras con TypeScript porque tienen más información sobre los tipos y las relaciones entre las diferentes partes del código.

    • Escalabilidad: TypeScript es especialmente útil en proyectos grandes y complejos, donde el código tiende a ser más difícil de mantener.

  3. Características Avanzadas del Lenguaje:

    • Interfaces y tipos personalizados: TypeScript permite definir interfaces y tipos personalizados, lo que ayuda a crear estructuras de datos claras y concisas.

    • Decoradores y metaprogramación: TypeScript soporta decoradores y otras características avanzadas que no están disponibles en JavaScript estándar.

  4. Compatibilidad con el Ecosistema JavaScript:

    • Transpilación a JavaScript: TypeScript se transpila a JavaScript, lo que significa que puedes usarlo en cualquier entorno donde se pueda ejecutar JavaScript, incluyendo navegadores web y Node.js.

    • Interoperabilidad: Puedes usar bibliotecas y frameworks de JavaScript existentes con TypeScript, y puedes gradualmente migrar un proyecto de JavaScript a TypeScript.

  5. Mejor Colaboración:

    • Consistencia en equipos grandes: TypeScript ayuda a equipos grandes a mantener un código más consistente y predecible.

    • Documentación implícita: Los tipos actúan como una forma de documentación implícita, haciendo que el código sea más fácil de entender para otros desarrolladores.

Nota: Las validaciones de Typescript al ser estáticas no se pueden hacer durante el runtime de la aplicación.

Como funciona

Tipos Primitivos

  1. string: Representa una cadena de texto.

    let name: string = "John Doe";
  2. number: Representa números, ya sean enteros o de punto flotante.

    let age: number = 30;
  3. boolean: Representa valores de verdad (true o false).

    let isActive: boolean = true;
  4. null y undefined: Representan la ausencia de valor.

    let value: null = null;
    let notAssigned: undefined = undefined;

Type

Se usa para definir tipos de variables y generalmente se usa para tipos primitivos.

type UserID = string | number | boolean;

Tipos Compuestos

  1. Arreglos (Array): Representa una lista de elementos del mismo tipo.

    let numbers: number[] = [1, 2, 3];
    // o
    let strings: Array<string> = ["a", "b", "c"];
    1. ReadonlyArray: Este tipo de dato es un array, pero la principal diferencia con los arrays normales es que no existe ninguno de los métodos de mutación, tales como pop, push, shift, etc.

      const arr: ReadonlyArray = [1,2,3,4,5];

  2. Tuplas (Tuple): Representa un arreglo con un número fijo de elementos de tipos específicos.

    let person: [string, number] = ["Alice", 25];
  3. Objetos (Object): Representa una colección de propiedades con valores de tipos específicos.

    let person: { name: string; age: number } = {  name: "Bob",  age: 40};

Tipos Especiales

  1. any: Desactiva la verificación de tipos, permitiendo cualquier valor. Úsalo con precaución.

    let anything: any = "Hello";
    anything = 42;
  2. unknown: Similar a any, pero más seguro porque aún requiere una verificación de tipo antes de usarlo.

    let notSure: unknown = 4;
    if (typeof notSure === "number") {  
        let num: number = notSure; 
        // Necesita verificación
    }
    1. Unknown type, este tipo de dato es la mejora de any, ya que nos da la flexibilidad que en ocasiones queremos pero sin apagar por completo el análisis de código estático. unknown nos fuerza a hacer una verificación de typeof.

      Comparar con aserción de tipo:

      typeof input === "string | object | number";

      Un array:

      Array.isArray(input);

      Otra cosa que podemos hacer para asignar un tipo cuando no lo conocemos es, por ejemplo:

      class ValueService { ... }
      class FakeValueService { ... }
      class MasterService {
        constructor(
          private valueService: ValueService
        ) { }
        ...
      }
      ...
      const fakeValueService = FakeValueService();
      const masterService = new MasterService(fakeValueService as unknown as ValueService);

  3. void: Representa la ausencia de un valor, comúnmente utilizado en funciones que no retornan nada.

    function logMessage(message: string): void {  console.log(message);}
  4. never: El tipo de dato never, más que todo sirve para tipar a una función que nunca va a finalizar o sencillamente que pueda terminar el programa en el caso de lanar una excepción.

    function error(message: string): never {  throw new Error(message);}

Cast

Pasar de un tipo de dato a otro.

Podemos definir como queremos que sea tratado un tipo de dato, le decimos a TypeScript que confíe en nuestro tipado. Que trate a esa variable como ese tipo de dato que le especificamos.

(variableName as dataType)

Angle bracket

Es lo mismo que as pero con otra sintaxis.

(<dataType>variableName)
let x: unknown = 'hello'; 
console.log((x as string).length);
console.log(<string>x).length);

Tipos Literales

Los tipos literales permiten especificar valores exactos que una variable puede tener.

let direction: "north" | "south" | "east" | "west";
direction = "north"; 
// Correctodirection = "up"; 
// Error: Type '"up"' is not assignable to type '"north" | "south" | "east" | "west"'.

Tipos Unión y Tipos Intersección

  1. Unión (Union): Permite que una variable tenga más de un tipo.

    let id: number | string;
    id = 101;
    id = "202";
  2. Intersección (Intersection): Combina múltiples tipos en uno solo.

    interface Person {  name: string;}
    interface Employee {  employeeId: number;}
    type EmployeePerson = Person & Employee;
    let employee: EmployeePerson = {  
        name: "John",  employeeId: 123
    };

Tipos de Funciones

Puedes definir los tipos de entrada y salida de una función.

function add(a: number, b: number): number {  return a + b;}

Enum

Set de conjunto de opciones

enum Estaciones { 
    primavera = "Primavera", 
    verano = "Verano", 
    otonio = "Otoño", 
    invierno = "Invierno", 
}

Sobrecarga de funciones

type customType = string | string[];

function parseStr(arg: string): string[]
function parseStr(arg: string[]): string
// any é unknown, siempre van al final
function parseStr(arg: any): customType {
    // code here...
}

Interfaces

Las interfaces funcionan muy similar a como lo hace type, pero en las interfaces solo aplica para los objetos y pueden ser heredadas.

interface EmployeeModel {
  id: number;
  name: string;
  lastName: string;
  salary: number;
  company: {
    id: number;
     name: string;
  }	
}

DTOs Es una abreviatura para referirnos a Data Transfer Objects son separados en archivos aparte.

interface EmployeeModelDto extends Omit<Employee, 'id' | 'name'> {
  companyId: number;
}

Omit y Pick type Estos tipos de datos nos permiten crear nuevas interfaces basadas de otras, pero omitiendo o seleccionando solo ciertos valores.

Partial & Required Estos dos tipos de datos nos sirven para declarar que todos los campos de una interfaz son opcionales u obligatorios.

interface Product {
  title: string;
  price: number;
  category: string;
  size?: string;
}

type UpdateProduct = Partial<Product>
type StrictProduct = Required<Product>

Readonly Con esta propiedad le decimos TypeScript que todos los parámetros solamente sean de lectura. Ejemplos:

type TypeName = Readonly;

interface Example {
  readonly property1: string;
  property2: number;
}

interface Example {
  property1: Readonly<string>;
  property2: number;
}

interface InterfaceName extends Readonly<OtherInterface> {
  // statements
}

Tipos de Utilidad

TypeScript ofrece varios tipos de utilidad para transformar y combinar tipos.

  • Partial<T>: Hace que todas las propiedades de T sean opcionales.

  • Required<T>: Hace que todas las propiedades de T sean requeridas.

  • Readonly<T>: Hace que todas las propiedades de T sean de solo lectura.

  • Pick<T, K>: Selecciona un subconjunto de las propiedades de T.

  • Omit<T, K>: Excluye un subconjunto de las propiedades de T.

interface Person {  name: string;  age?: number;}
type PartialPerson = Partial<Person>;
type RequiredPerson = Required<Person>;
type ReadonlyPerson = Readonly<Person>;
type NameOnly = Pick<Person, "name">;
type AgeExcluded = Omit<Person, "age">;

Tipado por indice

interface Human {
  name: string;
  age: number;
  isAlien: boolean;
}

function createHuman(name: Human["name"]) {
  // code
}

Diferencias Clave Enum, Type e Interface

  1. Propósito y Uso:

    • enum: Utilizado para definir un conjunto finito de valores constantes.

    • type: Utilizado para crear alias de tipos, tipos compuestos y complejos.

    • interface: Utilizado para definir la estructura de objetos y puede ser extendida e implementada.

  2. Herencia y Extensión:

    • enum: No admite herencia.

    • type: No admite herencia, pero puede combinarse usando Union y Intersection.

    • interface: Admite la herencia múltiple y la implementación en clases.

  3. Flexibilidad:

    • enum: Menos flexible, se utiliza principalmente para valores constantes.

    • type: Muy flexible y puede ser utilizado para definir cualquier tipo de dato.

    • interface: Más estructurado, ideal para definir la forma de objetos.

  4. Compatibilidad:

    • En general, interface y type son intercambiables en muchos casos, pero interface es preferido para definir la estructura de objetos debido a su capacidad de extensión y mejor integración con la programación orientada a objetos.

Class ES6 y typescript

Se pueden declarar las variables de una clase de esta forma en el contructor (es necesario especificar si es pública o privada)

constructor (
  public year: number = 1993,
  public month: number = 7,
  private day: number = 3
) {}
  • Protected: es un modificador de acceso que permite que los atributos y métodos de la clase sean accesibles desde la misma clase y desde las clases que heredan de esta.

  • Private: acceso de la misma clase.

  • super: La palabra clave super es usada para acceder y llamar funciones del padre de un objeto.

Abstract e implements

En TypeScript, abstract y implements son dos palabras clave que se utilizan para trabajar con clases y interfaces de una manera que facilita la programación orientada a objetos. Estas herramientas permiten definir y garantizar contratos de implementación y comportamientos comunes en jerarquías de clases.

Clases Abstractas (abstract)

Una clase abstracta es una clase que no se puede instanciar directamente. Se utiliza como una base para otras clases. Las clases abstractas pueden contener métodos abstractos (métodos sin implementación) y métodos concretos (métodos con implementación).

Las clases abstractas son tan genericas que no tiene sentido que sean instanciadas. Abstract se puede usar como interface también, ya que con interface no se puede tener atributos o métodos private o protected. Estos solo pueden se public.

Características de las Clases Abstractas

  1. No Instanciables: No se pueden crear instancias directamente de una clase abstracta.

  2. Métodos Abstractos: Pueden contener métodos sin implementación que deben ser implementados por las clases derivadas.

  3. Métodos Concretos: Pueden contener métodos con implementación que pueden ser heredados o sobrescritos por las clases derivadas.

  4. Propiedades Abstractas: Pueden definir propiedades abstractas que deben ser implementadas por las clases derivadas.

Ejemplo de Clase Abstracta

abstract class Animal {  
    constructor(public name: string) {}  
    // Método abstracto: debe ser implementado por las clases derivadas  
    abstract makeSound(): void;  
    // Método concreto: puede ser heredado o sobrescrito  
    move(): void {    console.log(`${this.name} is moving.`);  }
}

class Dog extends Animal {  
    constructor(name: string) {    
        super(name);  
    }  
    // Implementación del método abstracto  
    makeSound(): void {    
        console.log(`${this.name} says: Woof!`);  
    }
}
    
const myDog = new Dog("Buddy");
myDog.makeSound(); // Buddy says: Woof!
myDog.move(); // Buddy is moving.

Interfaces (interface) y implements

Una interfaz en TypeScript define un contrato que las clases deben seguir. Las interfaces pueden declarar métodos y propiedades sin proporcionar implementaciones. Las clases que implementan una interfaz deben proporcionar implementaciones para todos los métodos y propiedades declaradas en la interfaz.

Características de las Interfaces

  1. Contrato de Implementación: Define un conjunto de métodos y propiedades que una clase debe implementar.

  2. Sin Implementación: No pueden contener implementaciones de métodos.

  3. Herencia Múltiple: Una clase puede implementar múltiples interfaces.

  4. Extensión: Las interfaces pueden extender otras interfaces.

Ejemplo de Interface y implements

interface Flyable {  
    fly(): void;
}
interface Swimmable {  
    swim(): void;
}
class Bird implements Flyable {  
    constructor(public name: string) {}  
    // Implementación del método de la interfaz Flyable  
    fly(): void {    
        console.log(`${this.name} is flying.`);  
    }
}
class Fish implements Swimmable {  
    constructor(public name: string) {}  
    // Implementación del método de la interfaz Swimmable  
    swim(): void {    
        console.log(`${this.name} is swimming.`);  
    }
}
class Duck implements Flyable, Swimmable {  
    constructor(public name: string) {}  
    // Implementación de los métodos de las interfaces Flyable y Swimmable  
    fly(): void {    
        console.log(`${this.name} is flying.`);  
    }      
    swim(): void {    
        console.log(`${this.name} is swimming.`);  
    }
}
const myBird = new Bird("Parrot");
myBird.fly(); // Parrot is flying.
const myFish = new Fish("Goldfish");
myFish.swim(); // Goldfish is swimming.
const myDuck = new Duck("Donald");
myDuck.fly(); // Donald is flying.
myDuck.swim(); // Donald is swimming.

Uso Combinado de Clases Abstractas e Interfaces

A menudo, se utilizan clases abstractas e interfaces en combinación para definir estructuras de código más robustas y flexibles.

Ejemplo Combinado

interface Drivable {  
    drive(): void;
}
abstract class Vehicle implements Drivable {  
    constructor(public brand: string) {}  
    // Método abstracto: debe ser implementado por las clases derivadas  
    abstract startEngine(): void;  
    // Implementación del método de la interfaz Drivable  
    drive(): void {    
        console.log(`${this.brand} is driving.`);  
    }
}
class Car extends Vehicle {  
    constructor(brand: string) {    
        super(brand); 
    }  
    // Implementación del método abstracto  
    startEngine(): void {    
        console.log(`${this.brand} engine started.`);  
    }
}
const myCar = new Car("Toyota");
myCar.startEngine();// Toyota engine started.
myCar.drive(); // Toyota is driving.

Resumen

  • Clases Abstractas (abstract):

    • No se pueden instanciar directamente.

    • Pueden contener métodos y propiedades abstractas (sin implementación).

    • Pueden contener métodos y propiedades concretas (con implementación).

  • Interfaces (interface):

    • Definen contratos de implementación.

    • No pueden contener implementaciones de métodos.

    • Pueden ser implementadas por las clases usando la palabra clave implements.

    • Pueden ser extendidas por otras interfaces.

  • implements:

    • Utilizado por las clases para declarar que implementan una o más interfaces.

    • Obliga a la clase a proporcionar implementaciones para todos los métodos y propiedades de las interfaces.

El uso de clases abstractas e interfaces en TypeScript permite crear jerarquías de clases flexibles y bien estructuradas, facilitando la reutilización de código y la adherencia a principios de diseño orientado a objetos como el principio de sustitución de Liskov y la segregación de interfaces.

Patron Singleton

Con typescript se puede crear un constructor privado usando el patron Singleton, nos previene crear múltiples instancias de una clase.

export class MyService {
    static instance: MyService | null = null;

    private constructor(
      private name: string
    ) {}

    get Name() {
      return this.name;
    }

    static create(name: string) {
      if (MyService.instance === null) {
        console.log('Creating new instance');
        MyService.instance = new MyService(name);
      }
      return MyService.instance;
    }
  }

const myService1 = MyService.create('MyService1');
const myService2 = MyService.create('MyService2');
console.log(myService1 === myService2); //* true

Genéricos

Un genérico es como un parámetro para tipos. Puedes pensar en los genéricos como una forma de decir "este código funcionará con cualquier tipo, solo dime qué tipo será cuando lo uses". En lugar de definir una función que solo funcione con un tipo específico, usas un genérico para que la función funcione con diferentes tipos de datos sin perder la seguridad de tipos.

Ejemplo Simple de una Función Genérica

Supongamos que queremos crear una función que tome un argumento y simplemente lo devuelva:

function identity<T>(value: T): T {
    return value;
}

En este ejemplo:

  • T es un parámetro de tipo genérico. Podría ser cualquier nombre de variable (a menudo se usan T, U, V, etc.).

  • value: T significa que la función tomará un argumento value de cualquier tipo T.

  • : T después de la firma de la función indica que el tipo de retorno de la función será del mismo tipo T.

Puedes usar esta función con diferentes tipos de datos:

let num = identity<number>(42); // num es de tipo number
let str = identity<string>("Hello"); // str es de tipo string
let bool = identity<boolean>(true); // bool es de tipo boolean

Inferencia de Tipos

TypeScript es capaz de inferir el tipo genérico automáticamente en muchos casos, por lo que no siempre es necesario especificar el tipo explícitamente:

let num = identity(42); // TypeScript infiere que T es number
let str = identity("Hello"); // TypeScript infiere que T es string

Genéricos en Clases

Puedes también usar genéricos en clases para crear estructuras de datos más flexibles:

class Box<T> {
    private contents: T;

    constructor(value: T) {
        this.contents = value;
    }

    getContents(): T {
        return this.contents;
    }
}

const numberBox = new Box<number>(123);
console.log(numberBox.getContents()); // 123

const stringBox = new Box<string>("TypeScript");
console.log(stringBox.getContents()); // "TypeScript"

En este ejemplo, Box<T> es una clase genérica que puede contener cualquier tipo T. Puedes crear cajas que contengan number, string, u otros tipos.

Genéricos en Interfaces

También puedes usar genéricos en interfaces para describir estructuras de datos más complejas:

interface Pair<T, U> {
    first: T;
    second: U;
}

let pair: Pair<number, string> = {
    first: 42,
    second: "The answer"
};

console.log(pair.first); // 42
console.log(pair.second); // "The answer"

Aquí, Pair<T, U> es una interfaz genérica que define una estructura de datos que contiene dos propiedades, first de tipo T y second de tipo U.

Restringiendo a tipos con una propiedad específica

Supongamos que quieres crear una función que opere sobre objetos que tengan una propiedad length. Puedes usar extends para asegurarte de que solo se puedan pasar objetos que tengan esa propiedad.

typescriptCopy codefunction logLength<T extends { length: number }>(value: T): void {
    console.log(value.length);
}

logLength("Hello, world!"); // 13 - Funciona porque los strings tienen 'length'
logLength([1, 2, 3, 4, 5]); // 5 - Funciona porque los arrays tienen 'length'
logLength({ length: 10 }); // 10 - Funciona porque el objeto tiene una propiedad 'length'

// logLength(42); // Error: 'number' no tiene la propiedad 'length'
// logLength({ size: 10 }); // Error: El objeto no tiene la propiedad 'length'

En este ejemplo:

  • La función logLength acepta un argumento value de tipo T.

  • El tipo T está restringido a tipos que tienen una propiedad length de tipo number.

  • Intentar pasar un valor que no cumpla con esta restricción resultará en un error de compilación.

Ejemplo 2: Restringiendo a tipos derivados de una interfaz

Puedes usar extends para limitar los tipos genéricos a aquellos que extienden de una interfaz específica. Esto asegura que los tipos genéricos tengan ciertas propiedades y métodos definidos en esa interfaz.

interface Person {
    name: string;
    age: number;
}

function greet<T extends Person>(person: T): void {
    console.log(`Hello, ${person.name}. You are ${person.age} years old.`);
}

const john = { name: "John", age: 30 };
greet(john); // Funciona porque 'john' cumple con la interfaz 'Person'

const jane = { name: "Jane", age: 25, job: "Engineer" };
greet(jane); // Funciona porque 'jane' cumple con la interfaz 'Person', aunque tiene propiedades adicionales

// const notAPerson = { job: "Doctor" };
// greet(notAPerson); // Error: 'notAPerson' no tiene las propiedades 'name' y 'age'

En este ejemplo:

  • La función greet solo acepta argumentos que extiendan de la interfaz Person.

  • El objeto pasado a greet debe tener las propiedades name y age.

  • Si intentas pasar un objeto que no cumple con la interfaz Person, TypeScript generará un error.

Ejemplo 3: Restringiendo a tipos que extienden de una clase

Puedes también restringir tipos genéricos a aquellos que extienden de una clase específica. Esto permite que el genérico use métodos y propiedades definidos en la clase base.

class Animal {
    constructor(public name: string) {}
    move(distance: number) {
        console.log(`${this.name} moved ${distance} meters.`);
    }
}

class Dog extends Animal {
    bark() {
        console.log("Woof! Woof!");
    }
}

function makeMove<T extends Animal>(animal: T, distance: number): void {
    animal.move(distance);
}

const dog = new Dog("Rex");
makeMove(dog, 10); // "Rex moved 10 meters."

// const car = { model: "Toyota", move: (distance: number) => console.log(`Car moved ${distance} meters.`) };
// makeMove(car, 20); // Error: 'car' no extiende de 'Animal'

En este ejemplo:

  • La función makeMove está restringida a aceptar tipos que extienden de la clase Animal.

  • Esto asegura que cualquier argumento pasado a makeMove tendrá acceso al método move.

  • Intentar pasar un objeto que no extienda de Animal resultará en un error.

Ejemplo 4: Múltiples restricciones con extends

Puedes restringir un tipo genérico para que extienda de múltiples tipos usando una intersección de tipos.

interface HasLength {
    length: number;
}

interface Printable {
    print(): void;
}

function printAndLogLength<T extends HasLength & Printable>(item: T): void {
    console.log(item.length);
    item.print();
}

const book = {
    length: 500,
    print: () => console.log("Printing book..."),
};

printAndLogLength(book); // Funciona: book tiene 'length' y 'print'

// const nonPrintable = { length: 10 };
// printAndLogLength(nonPrintable); // Error: no tiene 'print'

En este ejemplo:

  • La función printAndLogLength acepta un argumento item de tipo T.

  • T está restringido a tipos que extienden tanto de HasLength como de Printable.

  • Esto asegura que item tendrá tanto la propiedad length como el método print.

Declaration Files

En TypeScript, las declaration files (archivos de declaración) o simplemente definitions son archivos con la extensión .d.ts que proporcionan descripciones de los tipos presentes en archivos JavaScript. Estos archivos permiten a TypeScript conocer las formas y tipos de las entidades definidas en archivos JavaScript, lo que es especialmente útil cuando se trabaja con bibliotecas de JavaScript que no están escritas en TypeScript.

Propósito de los Declaration Files

  1. Interoperabilidad con JavaScript: Permiten que TypeScript pueda interactuar con bibliotecas y módulos de JavaScript proporcionando información de tipos.

  2. Mejora de la Experiencia de Desarrollo: Proporcionan autocompletado, documentación en línea y verificación de tipos en los editores de código.

  3. Evitan Errores en Tiempo de Desarrollo: Ayudan a detectar errores en tiempo de desarrollo al verificar los tipos de datos.

Creación de Declaration Files

Puedes crear tus propios archivos de declaración o usar los que están disponibles en la comunidad a través de DefinitelyTyped.

Ejemplo de un Archivo de Declaración

Supongamos que tienes una biblioteca JavaScript llamada myLibrary.js:// myLibrary.jsfunction greet(name) { return `Hello, ${name}!`;}

Puedes crear un archivo de declaración llamado myLibrary.d.ts para describir esta función:

// myLibrary.d.ts
declare function greet(name: string): string;

Uso del Archivo de Declaración

Ahora puedes usar la función greet en un archivo TypeScript con verificación de tipos:

// main.ts
/// <reference path="./myLibrary.d.ts" />
greet("World"); 
// Correctogreet(42); 
// Error: Argument of type 'number' is not assignable to parameter of type 'string'.

DefinitelyTyped y @types

DefinitelyTyped es un repositorio que contiene archivos de declaración para muchas bibliotecas populares de JavaScript. Puedes instalar estos archivos de declaración mediante npm utilizando el prefijo @types.

Ejemplo de Instalación

Para instalar los tipos para una biblioteca como lodash, puedes usar:

npm install --save-dev @types/lodash

Esto instalará los tipos necesarios para lodash y te permitirá usar la biblioteca con verificación de tipos en TypeScript.

Ejemplo Completo

Si quisieras utilizar lodash en un proyecto TypeScript, primero instalarías tanto lodash como sus tipos:

npm install lodashnpm install --save-dev @types/lodash

Luego podrías usar lodash en tu código TypeScript con autocompletado y verificación de tipos:

// main.ts
import * as _ from 'lodash';
const result = _.chunk(['a', 'b', 'c', 'd'], 2);
console.log(result); // [['a', 'b'], ['c', 'd']]

Last updated