Te llevará a ver las nuevas funciones de TypeScript 5.0

1. Escribe al frente

TypeScript 5.0 se lanzó el 16 de marzo de 2023 y trae muchas funciones nuevas y optimiza el rendimiento. Echemos un vistazo a los cambios más importantes en la nueva versión de TypeScript.

2. Nuevas características

2-1 Optimización de la velocidad y el volumen del paquete

La primera es la mejora del rendimiento de la nueva versión. La versión 5.0 tiene una buena optimización en términos de velocidad de compilación y volumen del paquete. La siguiente tabla muestra la mejora del rendimiento de la versión 5.0 en comparación con la 4.9:

proyecto El grado de optimización relativo a TS 4.9
tiempo de compilación de la interfaz de usuario del material 90%
Tiempo de inicio del compilador de TypeScript 89%
Tiempo de autoconstrucción del compilador de TypeScript 87%
Tiempo de compilación web de Outlook 82%
Tiempo de compilación del código VS 80%
tamaño del paquete npm 59%

¿Qué hace exactamente TypeScript 5.0 para optimizar el rendimiento?

  • La primera es namespacemigrar a module, que aplica más características de las herramientas de compilación modernas para optimizar (como la elevación del alcance) y eliminar parte del código obsoleto, lo que reduce el tamaño del paquete en aproximadamente 26,4 MB.
  • En segundo lugar, TS simplifica los datos almacenados en los objetos dentro del compilador y reduce el uso de memoria.
  • Luego se optimiza en algunas áreas específicas, como el uso ocasional en cierres varen lugar de leto constpara mejorar el rendimiento del análisis.

En general, la mayoría de los proyectos de TypeScript ven un aumento del rendimiento del 10 % al 20 % con TypeScript 5.0.

2-2 Nuevo estándar de decorador

Los decoradores son familiares para aquellos que escriben ts Aunque no es una característica estándar de js, ts ya admite decoradores "experimentales" en versiones anteriores. En la última versión 5.0, la sintaxis del decorador ya no será una sintaxis "experimental", y no es necesario agregar --experimentalDecoratorselementos de configuración a las opciones de compilación (aunque en la nueva versión, esta opción de compilación seguirá existiendo), TypeScript 5.0 Will admite de forma nativa la sintaxis del decorador!

Veamos un ejemplo de un decorador:

Primero tenemos una clase muy simple:

class Person {
    
    
  name: string;
  constructor(name: string) {
    
    
    this.name = name;
  }

  greet() {
    
    
    console.log(`Hello, my name is ${
      
      this.name}.`);
  }
}

const p = new Person("zy");
p.greet();

Queremos greetagregar algunos registros a las funciones de esta clase y registrar el nombre de la función que llama, por lo que la forma más fácil es hacer esto:

class Person {
    
    
  name: string;
  constructor(name: string) {
    
    
    this.name = name;
  }

  greet() {
    
    
    console.log("LOG: Entering method greet.");

    console.log(`Hello, my name is ${
      
      this.name}.`);

    console.log("LOG: Exiting method greet.");
  }
}

const p = new Person("zy");
p.greet();

Pero si queremos agregar funciones similares a más funciones, es muy adecuado usar decoradores, por ejemplo, podemos escribir uno loggedMethod, de la siguiente manera:

function loggedMethod(
  originalMethod: any,
  context: ClassMethodDecoratorContext
) {
    
    
  const methodName = String(context.name);

  function replacementMethod(this: any, ...args: any[]) {
    
    
    console.log(`LOG: Entering method '${
      
      methodName}'.`);
    const result = originalMethod.call(this, ...args);
    console.log(`LOG: Exiting method '${
      
      methodName}'.`);
    return result;
  }

  return replacementMethod;
}

De esta forma, podemos usar loggedMethodeste decorador para decorar esta función para lograr el efecto anterior:

class Person {
    
    
  name: string;
  constructor(name: string) {
    
    
    this.name = name;
  }

  @loggedMethod
  greet() {
    
    
    console.log(`Hello, my name is ${
      
      this.name}.`);
  }
}

const p = new Person("zy");
p.greet();

// Output:
//
//   LOG: Entering method 'greet'.
//   Hello, my name is zy.
//   LOG: Exiting method 'greet'.

Incluso podemos crear una "función que devuelve la función de decorador", para que podamos desarrollar más funciones personalizadas y más para el decorador, por ejemplo, quiero personalizar el prefijo de la cadena de salida a la consola:

function loggedMethod(headMessage = "LOG:") {
    
    
  return function actualDecorator(
    originalMethod: any,
    context: ClassMethodDecoratorContext
  ) {
    
    
    const methodName = String(context.name);

    function replacementMethod(this: any, ...args: any[]) {
    
    
      console.log(`${
      
      headMessage} Entering method '${
      
      methodName}'.`);
      const result = originalMethod.call(this, ...args);
      console.log(`${
      
      headMessage} Exiting method '${
      
      methodName}'.`);
      return result;
    }

    return replacementMethod;
  };
}

De esta manera, loggedMethodlo llamamos antes de que se use como decorador, para que podamos pasar una cadena personalizada como prefijo de la cadena de salida de la consola:

class Person {
    
    
  name: string;
  constructor(name: string) {
    
    
    this.name = name;
  }

  @loggedMethod("LOG:")
  greet() {
    
    
    console.log(`Hello, my name is ${
      
      this.name}.`);
  }
}

const p = new Person("zy");
p.greet();

// Output:
//
//   LOG: Entering method 'greet'.
//   Hello, my name is zy.
//   LOG: Exiting method 'greet'.

2-3 constParámetros de tipo

Al inferir el tipo de un objeto, ts normalmente elegirá un tipo genérico. Por ejemplo, en este caso namesel tipo de se infiere como string []:

type HasNames = {
    
     readonly names: string[] };
function getNamesExactly<T extends HasNames>(arg: T): T["names"] {
    
    
  return arg.names;
}

// Inferred type: string[]
const names = getNamesExactly({
    
     names: ["Alice", "Bob", "Eve"] });

No hay problema con la inferencia string [], pero debido a namesque es readonlysí, pero el tipo inferido no lo es readonly, esto causará algunos problemas. Aunque podemos as constarreglar esto agregando, así:

// The type we wanted:
//    readonly ["Alice", "Bob", "Eve"]
// The type we got:
//    string[]
const names1 = getNamesExactly({
    
     names: ["Alice", "Bob", "Eve"] });

// Correctly gets what we wanted:
//    readonly ["Alice", "Bob", "Eve"]
const names2 = getNamesExactly({
    
     names: ["Alice", "Bob", "Eve"] } as const);

Pero es engorroso escribir así, y es fácil de olvidar. Entonces, en TypeScript 5.0, podemos agregar constmodificadores directamente para escribir declaraciones de parámetros, convirtiendo la inferencia de tipo constante en valores predeterminados:

type HasNames = {
    
     names: readonly string[] };
function getNamesExactly<const T extends HasNames>(arg: T): T["names"] {
    
    
//                       ^^^^^
    return arg.names;
}

// Inferred type: readonly ["Alice", "Bob", "Eve"]
// Note: Didn't need to write 'as const' here
const names = getNamesExactly({
    
     names: ["Alice", "Bob", "Eve"] });

Detalles específicos: https://github.com/microsoft/TypeScript/pull/51865

2-4 extendsLos elementos de configuración admiten múltiples archivos de configuración

extendsEn mi opinión, los elementos de configuración admiten varios archivos de configuración y, en mi opinión, es una de las funciones más prácticas de TypeScript 5.0. Cuando solemos tsconfig.jsonadministrar varios proyectos, en muchos casos, las extensiones de configuración se realizarán en un archivo de configuración de "línea base", como el siguiente:

// packages/front-end/src/tsconfig.json
{
    
    
    "extends": "../../../tsconfig.base.json",
    "compilerOptions": {
    
    
        "outDir": "../lib",
        // ...
    }
}

Sin embargo, en muchos casos, querremos extender desde múltiples archivos de configuración, ¡pero TypeScript 4.9 y las versiones anteriores no son compatibles con esta función! Y la buena noticia es que Typescript 5.0 ahora permite que el campo extendido introduzca múltiples rutas de configuración. Por ejemplo, la siguiente forma de escribir:

// tsconfig1.json
{
    
    
    "compilerOptions": {
    
    
        "strictNullChecks": true
    }
}

// tsconfig2.json
{
    
    
    "compilerOptions": {
    
    
        "noImplicitAny": true
    }
}

// tsconfig.json
{
    
    
    "extends": ["./tsconfig1.json", "./tsconfig2.json"],
    "files": ["./index.ts"]
}

En este ejemplo, strictNullCheckstanto y noImplicitAnysurtirán efecto en la versión final tsconfig.json.

Tenga en cuenta que si hay conflictos de campo en estos archivos de configuración importados, los campos importados más tarde sobrescribirán los campos importados anteriormente.

Detalles específicos: https://github.com/microsoft/TypeScript/pull/50403

2 a 5. Todas las enumeraciones se convierten en enumeraciones conjuntas

Cuando TypeScript diseñó originalmente los tipos de enumeración, eran solo un conjunto de constantes numéricas con el mismo tipo, como la siguiente enumeración E:

enum E {
    
    
  Foo = 10,
  Bar = 20,
}

E.Foo, E.BarEn comparación con las variables ordinarias, lo único especial es que se puede asignar a cualquier cosa de tipo E. Aparte de eso, son casi numbersindistinguibles de los tipos, como este:

function takeValue(e: E) {
    
    }

takeValue(E.Foo); // works
takeValue(123); // error!

Las enumeraciones no se volvieron especiales hasta que TypeScript 2.0 introdujo el tipo literal de enumeración. Los tipos literales de enumeración dan a cada miembro de enumeración su propio tipo y convierten la enumeración en sí misma en una colección de cada tipo de miembro. También nos permiten referirnos solo a un subconjunto de tipos enumerados y limitar el alcance de esos tipos, como se muestra en la siguiente enumeración Color:

// Color is like a union of Red | Orange | Yellow | Green | Blue | Violet
enum Color {
    
    
    Red, Orange, Yellow, Green, Blue, /* Indigo */, Violet
}

// Each enum member has its own type that we can refer to!
type PrimaryColor = Color.Red | Color.Green | Color.Blue;

function isPrimaryColor(c: Color): c is PrimaryColor {
    
    
    // Narrowing literal types can catch bugs.
    // TypeScript will error here because
    // we'll end up comparing 'Color.Red' to 'Color.Green'.
    // We meant to use ||, but accidentally wrote &&.
    return c === Color.Red && c === Color.Green && c === Color.Blue;
}

Y en algunos escenarios, por ejemplo, cuando los miembros de la enumeración se inicializan con llamadas a funciones, TypeScript no puede calcular el conjunto de valores de enumeración y abandonará la enumeración conjunta y usará la estrategia de enumeración anterior en su lugar.

TypeScript 5.0 resuelve este problema al convertir todas las enumeraciones en enumeraciones de unión mediante la creación de un tipo único para cada miembro de la enumeración. De esta forma, nuestros valores de enumeración en todos los casos, serán enumeraciones de unión.

Detalles específicos: https://github.com/microsoft/TypeScript/pull/50528

2-6 Opciones --moduleResolutionde soporte de elementos de configuraciónbundler

TypeScript 4.7 presenta opciones --moduley elementos de configuración . Estas opciones imitan mejor las reglas de búsqueda para los módulos ECMAScript en Node.js. Sin embargo, este patrón tiene muchas limitaciones, por ejemplo, en los módulos ECMAScript en Node.js, cualquier importación relativa debe incluir la extensión de archivo:--moduleResolutionnode16nodenext

// entry.mjs
import * as utils from "./utils"; //  wrong - we need to include the file extension.

import * as utils from "./utils.mjs"; //  works

Pero con el desarrollo de la tecnología front-end, esta regla de búsqueda se ha vuelto obsoleta. La mayoría de las herramientas de empaquetado modernas utilizan una fusión del módulo ECMAScript y las reglas de búsqueda del módulo CommonJS en Node.js. Entonces, para emular la forma en que funcionan las herramientas de agrupación, TypeScript ahora presenta una nueva estrategia: --moduleResolution bundler.

{
    
    
    "compilerOptions": {
    
    
        "target": "esnext",
        "moduleResolution": "bundler"
    }
}

Si está utilizando herramientas de empaquetado como Vite, esbuild, swc, Webpack, Parcel, etc., bundleresta configuración será muy adecuada.

Detalles específicos: https://github.com/microsoft/TypeScript/pull/51669

2-7 Soporteexport type *

Cuando TypeScript 3.8 introdujo type import/export export _ from "module", export _ as xx from "module"las exportaciones de tipos como o no estaban permitidas. TypeScript 5.0 agregó soporte para estas dos sintaxis de exportación de tipos:

// models/vehicles.ts
export class Spaceship {
    
    
  // ...
}

// models/index.ts
export type * as vehicles from "./vehicles";

// main.ts
import {
    
     vehicles } from "./models";

function takeASpaceship(s: vehicles.Spaceship) {
    
    
  //  ok - `vehicles` only used in a type position
}

function makeASpaceship() {
    
    
  return new vehicles.Spaceship();
  //         ^^^^^^^^
  // 'vehicles' cannot be used as a value because it was exported using 'export type'.
}

Para obtener más información, consulte: https://github.com/microsoft/TypeScript/pull/52217

Supongo que te gusta

Origin blog.csdn.net/u011748319/article/details/129670957
Recomendado
Clasificación