Skip to content

Instantly share code, notes, and snippets.

@Kreator-97
Created April 4, 2025 20:28
Show Gist options
  • Save Kreator-97/2cc56d8d0b408740bfad5b132eb1dabb to your computer and use it in GitHub Desktop.
Save Kreator-97/2cc56d8d0b408740bfad5b132eb1dabb to your computer and use it in GitHub Desktop.

Revisions

  1. Kreator-97 renamed this gist Apr 4, 2025. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. Kreator-97 renamed this gist Apr 4, 2025. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  3. Kreator-97 created this gist Apr 4, 2025.
    669 changes: 669 additions & 0 deletions TS-introducción
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,669 @@
    # Manual de TypeScript

    ## Introducción
    TypesScript es un superset de JavaScript que le otorga características que lo hacen un lenguaje para escribir código mucho más robusto y escalable con el objetivo de tener la misma experencia de desarrollo de lenguajes más tradicionales como:

    - Java
    - C#
    - Objective-C

    Para conocer por que TypeScript es necesario para ser desarrollador web en estos momentos es necesario que conozcas las carencias de JavaScript.

    ### Carencias de JavaScript
    JavaScript es un lenguaje que originalmente fue creado con el propósito de realizar ciertas operaciones en el lado de cliente cuando el internet todavía no era lo demasiado rápido en aquella época. Por lo consiguiente, JavaScript tuvo un desarrollo no muy bien planeado y en el desarrollo actual, sufre de la carencia de las siguientes características.

    - Tipado de variables
    - Errores en tiempo de escritura (linter)
    - Autocompletado dependiendo de las variables
    - Clases y Módulos (ES6)
    - Validación de objetos dentro de objetos
    - Tipado de respuesta HTTP

    ### Características de TypeScript
    Debemos de conocer las características de TypeScript:

    - Es un superset
    - Es compatible
    - Transpila a código JavaScript
    - Añade clases en la OOP

    #### Superset
    Un superset nos ayuda a expandir las funcionalidades de un lenguaje, en este caso JavaScript, para lograr que este sea capaz de realizar el mismo trabajo de una forma más eficiente y ampliar el panorama de desarrollo.

    #### Compatibilidad
    Una cosa de la que no debes preocuparte es que todo el código de JavaScript es totalmente compatible en TypeScript, por lo que puedes ir aprendiendo TypeScript poco a poco e ir añadiendo sus mejores a medida que lo vayas dominando.

    #### Transpilar
    Todo el código escrito en TypeScript no es válido en el navegador web, por lo que necesitamos de alguna manera convertir el código escrito a JavaScript puro. Este proceso se conoce como transpilación. En el caso de JavaScript, todo el código es transpilado hacia una versión que es totalmente compatible con todos los navegadores.

    #### Clases en la OOP
    TypeScript soporta de forma más robusta la orientación a objetos de forma similar a lenguajes como Java o C#.

    ### Desventajas
    No todas las características de TypeScript nos ortogan ventajas, asi que veamos algunas de las desventajas de implementar TypeScript en tu proyecto:

    - Se tiene que transpilar
    - Se tiene que escribir más código

    ## Relación con JavaScript
    TypeScript es un superset de JavaScript en un sentido sintactico: siempre y cuando tu programa de JavaScript no tenga errores, será también un programa de TypeScript válido.

    Los archivos de TypeScript usan la extension `.ts` en lugar de `.js` de un archivo de JavaScript. Esto no significa que TypeScript sea un lenguaje diferente.

    Esto es de enorme ayuda si estás migrando código de JavaScript a TypeScript. Significa que no tienes que reescribir algo de tu código a otro lenguaje para comenzar a utilizar TypeScript y obtener los beneficios que provee. Esto no sería verdad si eliges reescribir to código en un lenguaje como Java. Esta migración amable es uno de los mayores beneficios de TypeScript.

    Todo los programas de JavaScript son programas de TypeScript válidos. Pero lo contrario no es cierto: hay programas de TypeScript que no son programas de JavaScript válido.

    Esto es porque TypeScript añade una sintaxis adicional para especificar tipos.

    Por ejemplo, este es un programa de TypeScript válido:
    ```TypeScript
    function greet(who:string) {
    console.log(`Hello ${who}`);
    }
    ```

    El `who: string` es una anotación de tipo que es específica de TypeScript.

    ## Compilar TypeScript
    Para compilar o generar nuestro archivo `.js` debemos de ejecutar el comando indicado para dicha tarea.

    Ejecutamos por consola el comando tsc seguido del archivo de `.ts` que queremos compilar.
    ```
    tsc <file.ts>
    ```

    ### Configuraciones
    Para crear nuestro archivo de configuración de TypeScript utilizamos el siguiente comando:
    ```
    tsc --init
    ```

    Esto nos creará un nuevo archivo llamado `tsconfig.json` con toda la configuración disponible para TypeScript.

    Cuando tenemos este archivo, compilar se vuelve más sencillo ya que no necesitamos indicar el nombre del archivo `.ts` que deseamos transpilar ya que esa información se encuentra en la configuración.

    ### Modo observador
    Cuando trabajamos en un proyecto, es muy común realizar múltiples cambios en diferentes archivos, pero en cada cambio debemos de realizar una compilación para poder verificar que nuestro código funciona. Entonces se puede volver demasiado tedioso tener que escribir el comando de compilación por consola cada vez que lo necesitemos.

    Para solventar eso, podemos poner al compilador en el modo de observador con el siguiente comando.
    ```
    tsc --watch
    ```

    Este modo te permite decirle al compilador que cada vez que vea un cambio en los archivos del proyecto, realize la compilación correspondiente.

    ### Generación de código
    A alto nivel, debemos de entender que tsc (TypeScript compiler) hace 2 cosas:

    1. Convierte la siguiente generación de TypeScript/JavaScript a una versión más antigua de JavaScript que funciona en navegadores (transpilado).
    2. Inspecciona tu código por errores de tipos.

    Algo muy importante que debes de entender es que la generación de código es independiente de los tipos, o dicho de otra manera, los tipos en tu código no afecta el JavaScript que TypeScript emite.

    ### Código con errores de tipos puede producir una salida
    Debido a que la salida es independiente del chequeo de tipos, significa que el código con errores de tipos puede producir una salida.

    Esto puede parecer un poco sorprendente debido a que si vienes de lenguajes como C o Java donde el chequeo de tipos y la salida van de la mano. Puedes pensar en todos los errores de TypeScript como en advertencias en esos lenguajes. Es parecido a indicar que existe una problema y que vale la pena investigarlo, pero no detiene la salida.

    ### Configuraciones avanzadas
    Mucho de las de configuración de TypeScript controlan donde buscar los archivos fuentes y que clase de código genera, pero unos pocos controlan el aspecto del lenguaje en si mismo. Esa son elecciones de diseño de alto nivel que la mayoría de los lenguajes no le permiten a sus usuarios. TypeScript se puede sentir como un lenguaje completamente diferente dependiendo de como este configurado. Para usarlo efectivamente, deberías comprender las más importantes de esas configuraciones: `noImplicitAny` y `strictNullChecks`

    ### noImplicitAny
    Controla si las variables deben de tener tipos conocidos. El siguiente código es válido cuando `noImplicitAny` está desactivado:

    ```TypeScript
    function add(a, b) {
    return a + b
    }
    ```

    Si revisas el tipo de la función add en tu editor, te revelará que tien TypeScript inferido sobre el tipo de esa función:

    ```TypeScript
    function add(a:any, b:any): any
    ```

    El tipo any desactiva efectivamente el inspector de tipos para el código que involucra esos parámetros. any es una herramienta útil, pero debería ser usada con preucación.

    Esos son llamados `implicit anys` debido a que tu nuncas has escrito la palabra `any`. Esto llega a ser un error cuando activas la opción `noImplicitAny`

    Estos errores pueden ser arreglados escribiendo explicítamente declaraciones de tipos, ya sea `:any` o un tipo más específico.

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

    TypeScript es el más provechoso cuando tiene información de tipos, así que deberías de asegurarte de colocar `noImplicitAny` siempre que sea posible. Para nuevos proyectos, deberías de comenzar con `noImplicitAny` activado, asi escribes tus tipos a medida que escribes tu código. Desactivarlo solo es apropiado si estás transicionando un projecto de JavaScript a TypeScript.

    ### strictNullChecks
    Controla si `null` and `undefined` son valores permitidos en todos los tipos. El siguiente código es válido cuando esta opción está apagada:

    ```TypeScript
    const x:number = null // ok, null is a valid number
    ```

    Pero dispara un error cuando está habilitada:
    ```TypeScript
    const x:number = null // Type 'null' is not assignable to type number
    ```

    Un error similar podría haber ocurrido si usabas undefined en lugar de null. Si quieres permitir null, puedes solucionar este error haciendo tu inteción explícita:
    ```TypeScript
    const x:number | null = null
    ```

    Si no deseas permitir null, necesitarás localizar de donde viene y añadir ya sea una verificación o una afirmación.

    ```TypeScript
    const el = document.getElementById('status')

    if( el ) {
    el.textContent = 'Ready' // ok, null ha sido excluido
    }

    el.!textContent = 'Ready' // ok, hemos afirmado que el no es null
    ```

    ## Tipos básicos
    Una de las metas del sistema de tipo de TypeScript es detectar código que lanzará una excepción en tiempo de ejecución, sin tener que ejecutar tu código. Cuando escuches que TypeScript es describido como un sistema estatico de tipo, es que se refiero a esto.

    TypeScript soporta los mismo tipos de datos que JavaScript, pero adicionalmente añade algunos nuevos que veremos más adelante.

    Antes de ver cada uno de los tipos de datos, necesitamos comprender que es el tipado estricto.

    ### Tipado estricto
    El tipado estricto nos obliga a indicar cual es el tipo de dato que puede contener una variable en el momento de la declaración. De ese modo, si le reasignamos el valor de una variable por otro de un tipo de dato distinto arrogará un error.

    ### Tipos primitivos
    En TypeScript soportamos los mismo tipos de datos que JavaScript que ya conocemos:
    - String
    - Number
    - Boolean
    - Symbol
    - null
    - undefined

    ### Tipos Compuestos
    Al igual que los primitivos, soportamos los mismo tipos de datos compuesto que son los siguientes:
    - Objetos literales
    - Arreglos
    - Funciones
    - Clases

    ### Nuevos tipos
    Por eso es que unicamente nos enfocaremos en los nuevos tipos de datos agregados por TypeScript:
    - Any
    - Interfaces
    - Genericos
    - Tuplas

    #### any
    El tipo any es un tipo de dato de TypeScript el cual le dice a la variable declarada con este tipo que cualquier tipo de dato es válido.

    Se recomienda que nunca se utilice este tipo de dato debido a que perdemos las características del tipado estricto en TypeScript. Su uso debe ser solamente de forma provisional, pero debe ser corregido más adelante por el tipo de dato correcto.

    ```JavaScript
    // bad
    let msg:any = '';

    // Good
    let username:string = '';
    ```

    #### Array
    Los array funcionan de la misma manera que en JavaScript pero con la diferencia de que TypeScript no nos dejará insertar un tipo de dato que no sea permitido, es decir, que si tenemos un arreglo que contienen strings, no podemos insertarle un dato númerico.

    ```JavaScript
    const cities = ['Mexico', 'Jalisco', 'Cancún', 'Tuxtla Gutierrez'];

    cities.push(4) // => Wrong!!
    ```

    Pero podemos inicializar el arreglo vacio e indicarle cuales serán los tipos de datos que podrán ser agregados dentro del arreglo.
    ```JavaScript
    const arr:(string || number || boolean)[] = [];
    ```

    Crear un arreglo con distintos tipos de datos puede ser considerado una mala práctica, debido a eso, lo mejor es indicarle solo un tipo:
    ```JavaScript
    const numbers:number[] = [];
    ```

    #### Tuplas
    Una tupla en TypeScript es un array de elementos que están tipados. De esta manera cada vez que haya que insertar un elemento se validará que dicho elemento coincida con el tipo de dato establecido en la tupla.

    ```JavaScript
    const hero:[string, number] = ['Dr strange', 100];
    ```

    #### Enum
    Las enumeraciones son una de las pocas características que tiene TypeScript que no es una extensión de JavaScript de nivel de tipo.

    Las enumeraciones permiten a un desarrollador definir un conjunto de constantes con nombre. El uso de enumeraciones puede hacer que sea más fácil documentar la intención o crear un conjunto de casos distintos. TypeScript proporciona enumeraciones numéricas y basadas en cadenas.

    ```JavaScript
    enum Direction {
    Up = 1,
    Down,
    Left,
    Right
    }
    ```

    Arriba, tenemos una enumeración numérica donde Up se inicializa con 1. Todos los siguientes miembros se incrementan automáticamente a partir de ese punto. En otras palabras, Direction.Up tiene el valor 1, Down tiene 2, Left tiene 3 y Right tiene 4.

    #### String enum
    Las enumeraciones de cadena son un concepto similar, pero tienen algunas diferencias sutiles de tiempo de ejecución como se documenta a continuación. En una cadena de enumeración, cada miembro debe inicializarse constantemente con una cadena literal o con otro miembro de cadena de enumeración.
    ```JavaScript
    enum Direction {
    Up = "UP",
    Down = "DOWN",
    Left = "LEFT",
    Right = "RIGHT"
    }
    ```

    #### void
    El tipo de dato void (vacio) es una forma que tiene el intérprete de TypeScript de indicar que una función no retornará ningún valor. Cuando una función no tiene un retorno explicíto, tendrá por defecto el valor de void (undefined en JavaScript). Es buena práctica indicar de forma explicita el valor de void cuando una función no retorne ningún valor, asi como en el siguiente ejemplo:
    ```JavaScript
    function printMessage(msg:any):void {
    console.log(msg);
    }
    ```

    Definir que una función retorna ningún valor te ayuda a documentar el código de proyecto y hace más fácil de comprender a tus funciones.

    #### never
    TypeScript introdujo un nuevo tipo never, que indica los valores que never ocurrirán.

    El tipo never se usa cuando está seguro de que algo nunca sucederá. Por ejemplo, escribe una función que no volverá a su punto final o siempre arrojará una excepción.

    ```JavaScript
    const error = (msg:string):never => {
    console.log(msg);
    throw new Error(msg);
    }

    error('Auxilio!');
    ```

    ### Casting
    El casting o casteo permite decirle al compilador de TypeScript que vas a tratar a cierto tipo de dato como otro tipo. Por ejemplo un uso común es cuando tenemos un valor de tipo any, pero nosotros sabemos que es un string, en ese caso se utiliza un casteo para indicar que ese valor de tipo any es un string.
    ```JavaScript
    const value:any = 'Foo bar';
    const length:number = (value.length as string).length;
    ```

    ### Más sobre los tipos en TypeScript
    Algo importante que debes de saber es que los tipos en TypeScript no están disponibles en tiempo de ejecución. Esto quiere decir que no pueden ser usados como valores por el interpréte de JavaScript debido a que esos valores no existen en el mismo JavaScript. Solo existen en el código TypeScript que por supuesto no es ejecutado.

    Debido a eso, no podemos utilizar tipos o interfaces para realizar comprobaciones en JavaScript donde se espera un valor real.

    ```TypeScript
    interface Rectangle {
    width: number;
    height: number;
    }

    const rectangle: Rectangle = {
    width: 10, height: 5,
    }

    rectangle instanceof Rectangle // => 'Rectangle' solo hace referencia a un tipo, pero aquí se usa como valor.
    ```

    Otro mito que muchos desarrolladores piensan es que los tipos de TypeScript tienen efecto alguno en el rendimiento final de un programa, lo cual es incorrecto.

    La razón es que el código de TypeScript no es ejecutado en el cliente, si no el JavaScript que es producido por el.

    El unico motivo por el cual pueda haber algún sobrecosto de rendimiento en un código generado por TypeScript sería cuando se genera algún código anterior que versus una implementación nativa. Esto quiere decir que TypeScript puede generar código que no está siendo soportando por navegadores antiguos seg;un el `target` indicado en la configuración de `tsconfig.json`. Cuando esto sucede, se podría dar el caso de que la salido del código generado sea menos eficienciente que el código nativo de un navegador que ya tiene esa implementación. Pero eso tiene poco o nada que ver como los tipos, ya que como vimos la generación de código es independiente de los tipos.

    ## Inferencia de Tipos
    TypeScript puede inferir el tipo de datos cuando este no es explícitamente anotado en su declaración de tipo. Por ejemplo:

    ```TypeScript
    let city = 'new york city'
    ```

    En el ejemplo anterior no indicamos el tipo de dato en cuestión, sin embargo, no necesitas hacerlo ya que TypeScript infiere que el tipo de ciudad es string. Lo infiere por medio de su valor inicial.

    Una de las metas del sistema de tipos es detectar el código que lanzará una excepción en tiempo de ejecución sin tener que ejecutar tu código. Cuando escuchas que describen a TypeScript como un sistema de tipo "estatico", es que se refiere a esto. El inspector de tipos no puede siempre destacar el código que lanzará excepciones, pero tratará.

    ## Funciones
    Las funciones de TypeScript tienen unas características importantes que no tiene las funciones tradicionales de JavaScript. Por ejemplo podemos indicar el tipo de valor de los parámetros de que recibe una función.

    ```TypeScript
    function sayHello(msg:string) {
    console.log(msg);
    }
    ```

    Este tipado estricto obliga a los desarrolladores a utilizar las funciones como están diseñadas originalmente, permitiendo menos flexibilidad pero ganando peso en un código más robusto y documentado. Gracias a las bondades de TypeScript ahora somos capaces de saber cuales son los tipos que recibe la función ahorrandonos tiempo en saber como funciona o se comporta la misma.

    ### Valor de retorno
    Todas las funciones deben de retorna un valor por defecto. En el caso de JavaScript, ese valor es `undefined`, pero en TypeScript se recomienda utilizar el tipo de dato `void` para indicar que un función tiene un valor de retorno vacío.

    Mejorando la función anterior:
    ```TypeScript
    function sayHello(msg):void {
    console.log(msg);
    return void;
    }
    ```

    ### Parámetros opcionales
    Cuando indicamos el tipo de dato que recibe el parámetro de una función también estamos indicando que dicho parámetro es obligatorio, ya que si no pasamos el valor correspondiente a dicho parámetro el compilador de TypeScript lanzará un error.

    Para señalar que el parámetro es opcional, lo indicamos como el simbolo `?`.

    ```TypeScript
    function sayHello(msg:string, upper:boolean):void {
    msg = (upper) ? msg.toUpperCase() : msg;
    console.log(msg);
    return void;
    }
    ```

    ### Type function
    En TypeScript existe el tipo de dato función que básicamente significa que el valor que tendrá un variable solo podrá ser una función.

    ```TypeScript
    let greet:Function;
    ```

    Adicionalmente podemos ser más específicos y crear una estructura más compleja en la que indicamos ciertas características que tendrá dicha función.
    ```TypeScript
    // También podemos hacerlo con la sintaxis de arrow function
    let greet:(msg:string) => void;
    ```

    ### Sobrecarga de funciones
    Algo que debes de entender sobre los tipos de TypeScript es que los tipos declarados pueden ser diferentes a los tipos en tiempo de ejecución.

    Lenguajes como C++ te permite definir multiples versiones de una función que difieren solo en los tipos de sus parámetros. Esto es llamado sobrecarga de funciones. Debido a que el comportamiento en tiempo de ejecución de tu código es independiente de los tipos de TypeScript, este constructo no es posible en TypeScript.

    Sin embargo, TypeScript si proporciona una facilidad parecida, pero opera enteramente al nivel de tipo. Puedes proporcionar multiples declaraciones para un función, pero solo una implementación:

    ```TypeScript
    function add(a:number, b:number): number;
    function add(a:string, b:number): string;

    function add(a, b) {
    return a + b
    }

    const three = add(1,2) // => 3
    const twelve = add('1', 2) // => '12'
    ```

    ### Structural Typing
    El tipado estructural (structural typing) es una característica habilitada en TypeScript que permite que un objeto sea compatible con un tipo de objeto distinto si cumple con las estructura declarada. Cuando se espera un objeto de cierto tipo en una función, podemos pasarle otro que cumpla con las propiedades de su tipo declarado si importar que sea un tipo diferentes, como por ejemplo cuando tiene más propiedades de las necesarias.

    Por ejemplo el siguiente tipo:
    ```TypeScript
    interface Vector2D {
    x: number;
    y: number;
    }
    ```

    Puedes escribir una función para calcular su longitud:
    ```TypeScript
    function calculateLength(v: Vector2D) {
    return Math.sqrt(v.x * v.x + v.y * v.y)
    }
    ```

    La función anterior recibe como parámetro un argumento del tipo `Vector2D` declarado anteriormente, pero podemos comprobar que puede recibir otro tipos tipos diferentes, siempre y cuando se cumpla con la estructura de `Vector2D`.

    Ejemplo:
    ```TypeScript
    interface NamedVector {
    name: string;
    x: number;
    y: number;
    }
    ```

    La función `calculateLength` puede funcionar con un objeto `NamedVector` debido a que tiene una propiedad `x` y `y` que son números.
    ```TypeScript
    const v:NamedVector = { x: 3, y: 4, name: 'Zee' }
    calculateLength(v) // ok
    ```

    Esto es interesante debido a que no declaraste una relación entre `Vector2D` y `NamedVector`. No tienes que escribir una implementación alternativa de `calculateLength` para `NamedVector`. Esto es posible porque la estructura de `NamedVector` fue compatible con `Vector2D`.

    ## Types
    Los types son tipos personalizados que te permiten crear estructuras definidas dentro de objetos. Es útil para verificar que todos los objetos cumplan con la estructura definida.
    ```JavaScript
    type Auto = {
    carroceria: string,
    modelo: string,
    puertas: number,
    pasajeros: number,
    conducir?: () => void,
    }
    ```

    ## Classes
    Las classes en TypeScript son mucho más complejas que las classes del estándar ES6, ya que cuentan con características que se asemejan más a la programación orientada a objetos de otros lenguajes como C# o Java.

    Para crear una clase utilizamos la palabra reservada `class` seguido del nombre de la clase en notación UpperCamelCase.

    Ejemplo:
    ```TypeScript
    class Auto {
    // ... propiedades
    }
    ```

    ### Propiedades
    Existen diferentes tipos de propiedades y métodos clasificados según su nivel de accesibilidad.

    - Públicas: Son accedidas desde cualquier instancia de la clase o dentro de la misma
    - Privadas: Son accedidas únicamente dentro de la definición de la clase
    - Estáticas: Pueden ser accedidas utilizando como referencia el objeto de la clase en si misma sin necesidad realizar ninguna instancia.
    - Protegidas: Son accedidas solamente en la definición de la clase y dentro de aquellas clase que son extendidas o heredadas

    Al momento de declarar una propiedad o un método es necesario especificar cual es su correspondiente tipo de accesibilidad con su respectiva keyword:

    - public
    - private
    - static
    - protected

    ```TypeScript
    class User {
    private password:string;
    public username:string;
    static getId = 'abc123';
    protected saludar(){ return `Hola me llamo ${this.username}`}

    constructor(password:string, username:string) {
    this.password = password;
    this.username = username;
    }
    }
    ```

    #### Propiedades opcionales
    Las propiedades opcionales son aquellas que no son requeridas al momento de realizar la instancia de una clase, por lo que necesitamos indicar en el método constructor mediante el operador `?`.

    ```TypeScript
    class User {
    public username:string;
    public email: string;
    private password: string;
    private numberPhone?: string;

    constructor(username:string, email:string, password:string, numberPhone?:number) {
    this.username = username;
    this.email = email;
    this.password = password;
    this.numberPhone = numberPhone;
    }
    }
    ```

    #### Asignación corta de propiedades
    Existe una forma de realizar una asignacíon de propiedades corta dentro de una clase utilizando los parámetros del método constructor. Con esto podemos simplificar el anterior ejemplo a lo siguiente:

    ```TypeScript
    class User {
    constructor (
    public username:string,
    public email:string,
    private password:string,
    private numberPhone?:number
    ) {}
    }
    ```

    ### Herencia
    La herencia de TypeScript funciona de forma muy similar a la de JavaScript. En ambas debemos de utilizar la keyword `extends` para indicar cual es la clase base de la cual vamos a heredar los métodos y propiedades.

    ```JavaScript
    class Person {
    constructor(
    public name: string,
    public lastName: string,
    ){}

    private getFullname() {
    return `${ this.name } ${this.lastName}`
    }
    }

    class Employee extends Person {}

    const employee = new Employee('Donato', 'Monzón');
    console.log(employee);
    ```

    Si observamos el resultado por consola vemos que obtenemos la nueva instancia wolverine que hereda desde la clase Avenger, pero sin necesidad de llamar al método super como se hace en JavaScript.

    Esto sucede por que el constructor de la clase `Xmen` no existe, entonces TypeScript llama al constructor de la clase `Avenger` en su lugar.

    Si necesitamos utilizar el método constructor de nuestra clase `Xmen` entonces será necesario llamar al método `super()`.

    ```TypeScript
    class Avenger {
    constructor(
    public name: string,
    public realName: string,
    ){
    console.log('Constructor Avenger llamado');
    }

    private getFullname() {
    return `${ this.name } ${this.realName}`;
    }
    }

    class Xmen extends Avenger {
    constructor (
    name:string,
    realName:string,
    public isMutant:boolean,
    ) {
    super(name, realName);
    console.log('constructor Xmen llamado');
    }
    }

    const wolverine = new Xmen('Wolverine', 'Logan', true);
    console.log(wolverine);
    ```

    ### Clases abstractas
    Una clase abstracta se declara con la keyword `abstract` antes de la definición de nuestra clase. La principal diferencia con las clases regulares es que las clases abstractas no pueden ser instanciadas, es decir, no podemos crear una variable o valor invocando directamente la clase por medio de la keyword `new`. En su lugar, el objetivo de la clase abstracta es servir como clase padre de la cual podamos heredar, con el propósito de tener una clase generica de base para crear clases más complejas.

    ```TypeScript
    abstract class Worker {
    constructor(
    public name:string,
    public position:string,
    ) {}
    }

    class Employee extends Worker {};
    const donato = new Employee('Donato', 'Developer');
    console.log(donato);
    ```

    ## Interfaces
    La interfaces es una forma que existe en TypeScript capaz de modelar objetos de forma muy similar a los `types aliases`. De hecho, las interfaces se parecen tanto a los types que se utilizan para el mismo propósito, pero hay una principal diferencia.

    Las interfaces pueden ser extendibles, es decir, podemos crear una intefaz base y crear otra que va a heredar sus propiedades de forma muy similar a las clase.

    Entonces, se podría definir a las interfaces entre el paso medio para una implementación entre los types y las clases.

    ```TypeScript
    interface Hero {
    name: string;
    age?: number;
    powers: number;
    getName?: () => string;
    }
    ```

    Las interfaces te ayudan a definir y marcar la estructura de ciertos objetos, pero no necesariamente indican que los métodos y propiedades definidos han sido implementados.

    ### Interfaces anidadas
    Algunas veces tendremos objetos que son muy complejos, por ejemplo, objetos dentro de objetos. Realizar interfaces anidadas es una técnica que va a permitir crear objetos con estructuras complejas y bien definidas.

    ```TypeScript
    interface Cliente {
    name:string;
    age:number;
    email:string;
    address?: Address;
    }

    interface Address {
    id: number;
    zip: string;
    city: string;
    }

    const client:Cliente = {
    name: 'Pablo',
    age: 25,
    email: '[email protected]',
    address: {
    id: 123,
    zip: '10000',
    city: 'Tuxtla',
    }
    }
    ```

    ### Implementar una clase desde una interfaz
    Las interfaces también pueden servir para realizar la implementación de una clase, es decir, obligar a una clase a que tenga la estructura definida de una interfaz.

    Para ello, utilizamos la keyword `implements` de forma similar a como aplicamos la herencia en `extends`:

    ```TypeScript
    interface SuperHero {
    name: string;
    realName: string;
    power:string;
    }

    class Hero implements SuperHero{
    constructor(
    public name: string,
    public realName: string,
    public power: string
    ) {}

    introduce() {
    return `My name is ${this.name} and my power is ${this.power}`;
    }
    }
    ```

    Recapitulando, `implements` se utiliza en una clase para forzar que tengan implementados todos los métodos y propiedades definidos en una interfaz.