Libro “Professional TypeScript. Desarrollo de aplicaciones JavaScript escalables "

imagenCualquier programador que trabaje con un lenguaje escrito dinámicamente dará fe de que la tarea de escalar el código es increíblemente difícil y requiere un gran equipo de ingenieros. Es por eso que Facebook, Google y Microsoft han creado la escritura estática para el código escrito dinámicamente.



Trabajando con cualquier lenguaje de programación, rastreamos las excepciones y leemos el código línea por línea para encontrar el problema y cómo solucionarlo. TypeScript le permite automatizar esta parte frustrante del proceso de desarrollo.



TypeScript, a diferencia de muchos otros lenguajes mecanografiados, está orientado a aplicaciones. Introduce nuevos conceptos que le permiten expresar ideas de forma más concisa y precisa, y crear fácilmente aplicaciones modernas escalables y seguras.



Boris Cherny ayuda a comprender todos los matices y capacidades de TypeScript, le enseña a eliminar errores y escalar el código.



Estructura del libro



Yo (el autor) he intentado brindarle una comprensión teórica de cómo funciona TypeScript y una buena cantidad de consejos prácticos de codificación.



TypeScript es un lenguaje práctico, por lo que la teoría y la práctica se complementan principalmente en el libro, pero los dos primeros capítulos cubren principalmente la teoría, y hacia el final solo se presenta la práctica.



Cubriremos los conceptos básicos como el compilador, el verificador de tipos y los tipos en sí. A continuación, discutimos sus variedades y operadores, y luego pasamos a temas avanzados como detalles del sistema de tipos, manejo de errores y programación asincrónica. Finalmente, le mostraré cómo usar TypeScript con sus marcos favoritos (frontend y backend), migrar un proyecto JavaScript existente a TypeScript y ejecutar una aplicación TypeScript en producción.



La mayoría de los capítulos terminan con una serie de ejercicios. Pruébelos usted mismo para comprender mejor el material. Las respuestas a ellos están disponibles aquí .



Migración por etapas de JavaScript a TypeScript



TypeScript se diseñó teniendo en cuenta la interoperabilidad de JavaScript. Entonces, si bien no es completamente sencillo, migrar a TypeScript sigue siendo una experiencia agradable, ya que le permite transformar su archivo de base de código a la vez, obtener un nivel más profundo de seguridad y confirmar tras confirmación, y sorprender a su jefe y compañeros de trabajo de lo poderoso que puede ser el código escrito de forma estática ...



En un nivel alto, el código base debe estar completamente escrito en TypeScript y fuertemente tipado, y las bibliotecas de JavaScript de terceros de las que depende deben ser de buena calidad y tener sus propios tipos fuertes. El proceso de codificación se duplicará con la captura de errores en tiempo de compilación y el rico sistema de autocompletado de TypeScript. Para lograr un resultado de migración exitoso, se necesitarán algunos pequeños pasos:



  • Agregue TSC al proyecto.
  • Empiece a comprobar los tipos de código JavaScript existente.
  • Mueva el código JavaScript a un archivo TypeScript por archivo.
  • Instale declaraciones de tipo para dependencias. Es decir, asigne tipos para dependencias que no los tengan, o escriba declaraciones de tipo para dependencias sin tipo y envíelas de vuelta a DefinitelyTyped1.
  • Habilite el modo estricto para la base de código.


Este proceso puede llevar un tiempo, pero verá inmediatamente mejoras en la seguridad y el rendimiento y otros beneficios más adelante. Echemos un vistazo a los pasos enumerados.



Paso 1: agregar TSC



Cuando trabaje con una base de código que combine TypeScript y JavaScript, primero deje que TSC compile los archivos JavaScript junto con los archivos TypeScript en la configuración tsconfig.json:



{
     "compilerOptions": {
     "allowJs": true
}


Este cambio por sí solo permitirá que TSC se utilice para compilar código JavaScript. Simplemente agregue TSC al proceso de compilación y ejecute cada archivo JavaScript a través de él, o siga ejecutando archivos JavaScript heredados a través del proceso de compilación y nuevos archivos TypeScript a través de TSC.



Con allowJs establecido en true, TypeScript no verificará los tipos en el código JavaScript actual, pero transpilará ese código a ES3, ES5 o la versión que se establece como destino en el archivo tsconfig.json usando el sistema de módulo que solicitó (en el campo del módulo json archivo). Se ha completado el primer paso. Confírmelo y dése una palmadita en la espalda: su código base ahora usa TypeScript.



Paso 2a: habilite la verificación de tipo de JavaScript (opcional)



Ahora que TSC está procesando JavaScript, ¿por qué no comprobar sus tipos? Incluso si no hay anotaciones de tipo explícitas, recuerde que TypeScript puede inferir tipos para código JavaScript de la misma forma que para el código TypeScript. Incluya la opción requerida en tsconfig.json:



{
     "compilerOptions": {
     "allowJs": true,
     "checkJs": true
}


Ahora, siempre que TypeScript compila un archivo JavaScript, intentará inferir y validar tipos tal como lo hace con el código TypeScript.



Si su base de código es grande y cuando habilita checkJs encuentra demasiados errores a la vez, apáguelo. En su lugar, habilite la verificación de archivos JavaScript uno a la vez agregando la directiva // @ ts-check (un comentario normal en la parte superior del archivo). O, si los archivos grandes arrojan un montón de errores que aún no desea corregir, deje checkJs habilitado y agregue la directiva // @ ts-nocheck para estos archivos.



TypeScript no puede inferir tipos para todo (por ejemplo, no infiere tipos para parámetros de función), por lo que inferirá muchos tipos en JavaScript como cualquiera. Si tiene habilitado el modo estricto en tsconfig.json (recomendado), es posible que prefiera permitir cualquiera implícito durante la migración. Agregue lo siguiente a tsconfig.json:



{
     "compilerOptions": {
     "allowJs": true,
     "checkJs": true,
     "noImplicitAny": false
}


Recuerde activar noImplicitAny nuevamente cuando haya terminado de migrar la mayor parte de su código a TypeScript. Esto probablemente encontrará muchos errores perdidos (a menos que sea Zenidar, un discípulo de la bruja de JavaScript Bavmorda, que puede verificar el tipo con el poder de su ojo mental con una poción de ajenjo).


Cuando TypeScript ejecuta código JavaScript, utiliza un algoritmo de inferencia más suave que el código TypeScript. A saber:



  • Todos los parámetros de función son opcionales.
  • Los tipos de propiedades de las funciones y clases se infieren en función de su uso (en lugar de tener que declararse por adelantado):



    class A {
        x = 0 // number | string | string[],    .
         method() {
                 this.x = 'foo'
         }
         otherMethod() {
                 this.x = ['array', 'of', 'strings']
         }
    
    }
  • Después de declarar un objeto, clase o función, puede asignarle propiedades adicionales. Detrás de escena, TypeScript hace esto generando un espacio de nombres apropiado para cada declaración de función y agregando automáticamente una firma de índice a cada objeto literal.


Paso 2b: agregue anotaciones JSDoc (opcional)



Es posible que tenga prisa y solo necesite agregar un tipo de anotación para una nueva función que se agregó a un archivo JavaScript antiguo. Puede usar la anotación JSDoc para hacer esto hasta que pueda convertir este archivo a TypeScript.



Probablemente hayas visto JSDoc antes. Estos son comentarios como este en la parte superior del código con anotaciones que comienzan con @, comoparam, @returns, etc. TypeScript comprende JSDoc y lo usa como entrada para el verificador de tipo junto con anotaciones de tipo explícitas.



Suponga que tiene un archivo de servicio de 3000 líneas (sí, lo sé, su "amigo" lo escribió). Le agrega una nueva función de servicio:



export function toPascalCase(word) {
       return word.replace(
             /\w+/g,
             ([a, ...b]) => a.toUpperCase() + b.join('').toLowerCase()
       )
}


Sin una conversión completa de utils.js a TypeScript, que seguramente revelará un montón de errores, solo puede anotar la función toPascaleCase, creando una pequeña isla de seguridad en el mar de JavaScript sin tipo:



/**
     * @param word {string}    .
     * @returns {string}   PascalCase
     */
export function toPascalCase(word) {
     return word.replace(
           /\w+/g,
           ([a, ...b]) => a.toUpperCase() + b.join('').toLowerCase()
     )
}


Sin esta anotación, JSDoc TypeScript inferiría el tipo toPascaleCase como (palabra: cualquiera) => cadena. Ahora, al compilar, sabrá que el tipo toPascaleCase es (palabra: cadena) => cadena. Y obtienes documentación útil.



Para obtener más información sobre las anotaciones JSDoc, visite la Wiki de TypeScript (https://github.com/Microsoft/TypeScript/wiki/JSDoc-support-in-JavaScript).



Paso 3: cambie el nombre de los archivos a .ts



Una vez que haya agregado TSC a su proceso de compilación y haya comenzado, opcionalmente, la verificación de tipos y la anotación de código JavaScript siempre que sea posible, es hora de cambiar a TypeScript.



Archivo por archivo, actualice los permisos de archivo de .js (o .coffee, es6, etc.) a .ts. Inmediatamente después de cambiar el nombre de los archivos en el editor, verá que aparecen amigos ondulados de color rojo que indican errores de tipo, casos omitidos, comprobaciones nulas olvidadas y errores tipográficos en los nombres de las variables. Hay dos formas de eliminarlos.



  1. . , , , . checkJs, noImplicitAny tsconfig.json, any , , JavaScript .
  2. .ts tsconfig.json ( strict false), . any, . . , strict (noImplicitAny, noImplicitThis, strictNullChecks . .), . ( .)


, TODO any any, . , :



// globals.ts
type TODO_FROM_JS_TO_TS_MIGRATION = any

// MyMigratedUtil.ts
export function mergeWidgets(
       widget1: TODO_FROM_JS_TO_TS_MIGRATION,
       widget2: TODO_FROM_JS_TO_TS_MIGRATION
): number {
       // ...
}


Ambos enfoques son bastante relevantes y depende de usted decidir cuál es preferible. TypeScript es un lenguaje mecanografiado paso a paso que está diseñado desde cero para interactuar con JavaScript sin escribir de la forma más segura posible. No importa si interactúa con JavaScript sin tipo o con TypeScript débilmente tipado, TypeScript fuertemente tipado siempre se asegurará de que la interacción sea lo más segura posible.



Paso 4: activa el rigor



Una vez que se ha portado una masa crítica de código JavaScript, querrá que sea todo en uno seguro utilizando los indicadores TSC más estrictos uno por uno (consulte el Apéndice E para obtener una lista completa de indicadores).



Cuando termine, puede desactivar las banderas TSC responsables de interactuar con JavaScript, confirmando que todo su código está escrito en TypeScript fuertemente tipado:



{
     "compilerOptions": {
     "allowJs": false,
     "checkJs": false
}


Esto revelará cualquier error de tipo restante. Corríjalos y obtenga una base de código segura e impecable por la que la mayoría de los ingenieros duros de OCaml le darían una palmada en la espalda.

Seguir estos pasos puede llevarle un largo camino al agregar tipos al código JavaScript que controla. Pero, ¿qué pasa con los códigos que no controlas tú? Como los instalados con NPM. Pero antes de estudiar esta pregunta, digamos un poco ...



Encontrar tipos para JavaScript



Cuando importa un archivo JavaScript desde un archivo TypeScript, TypeScript busca declaraciones de tipo para él usando el siguiente algoritmo (recuerde, en TypeScript, "archivo" y "módulo" se usan indistintamente):



  1. .d.ts , .js. .js.

    , :



    my-app/

    ├──src/

    │ ├──index.ts

    │ └──legacy/

    │ ├──old-file.js

    │ └──old-file.d.ts



    old-file ( ) index.ts:



    // index.ts

    import './legacy/old-file'



    TypeScript src/legacy/old-file.d.ts ./legacy/old-file.
  2. , allowJs checkJs true, .js ( JSDoc) any.




TSC-: TYPEROOTS ( )



TypeScript node modules/@types , (../node modules/@types . .). .



, typeRoots tsconfig.json , . , TypeScript typings node modules/@types:



{
     "compilerOptions": {
            "typeRoots" : ["./typings", "./node modules/@types"]
     }
}


types tsconfig.json, , TypeScript . , , React:



{
     "compilerOptions": {
             "types" : ["react"]
     }
}




Al importar un módulo JavaScript de terceros (el paquete NPM que instaló en los módulos de nodo), TypeScript usa un algoritmo ligeramente diferente:



  1. Busca una declaración de tipo local para el módulo y, si existe, la usa.



    Por ejemplo, la estructura de su directorio se ve así:



    my-app /

    ├──node_modules /

    │ └──foo /

    ├──src /

    │ ├──index.ts

    │ └──types.d.ts



    Así es como se ve type.d .ts:



    // types.d.ts
    declare module 'foo' {
          let bar: {}
          export default bar
    }


    Si luego importa foo, TypeScript usa la declaración del módulo externo en types.d.ts como fuente de tipo para él:



    // index.ts

    barra de importación de 'foo'
  2. package.json, . types typings, .d.ts, , .
  3. O recorrerá los directorios buscando el directorio de módulos de nodo / @ tipos, que contiene las declaraciones de tipo para el módulo.



    Por ejemplo, instaló React:



    npm install react --save

    npm install @ types / react --save-dev



    my-app /

    ├──node_modules /

    │ ├── @ types /

    │ │ └──react /

    │ └── react /

    ├──src /

    │ └──index.ts



    Al importar React, TypeScript encontrará el directorio @ types / react y lo usará como fuente de declaraciones de tipos para él:



    // index.ts

    import * as React from 'react'
  4. De lo contrario, irá a los pasos 1 a 3 del algoritmo de búsqueda de tipo local.


He enumerado bastantes pasos, pero se acostumbrará a ellos.



Sobre el Autor



Boris Cherny es ingeniero jefe y líder de producto en Facebook. Trabajó anteriormente en VC, AdTech y en una variedad de startups, la mayoría de las cuales no existen en la actualidad. Está interesado en lenguajes de programación, síntesis de código y análisis estático, y se esfuerza por compartir su experiencia con productos digitales con los usuarios. En su tiempo libre, organiza reuniones de clubes de TypeScript en San Francisco y mantiene un blog personal: performancejs.com . Puede encontrar la cuenta de GitHub de Boris en github.com/bcherny .



»Más detalles sobre el libro se pueden encontrar en el sitio web del editor

» Tabla de contenido

» Extracto



para Habitans 25% de descuento en cupón - TypeScript



Tras el pago de la versión impresa del libro, se envía un libro electrónico al correo electrónico.



All Articles