Escritura estática dinámica en TypeScript

 

 

 

  • Diseño de arquitectura de componentes de interfaz de usuario y tokens, con Nathan Curtis
  • Creación y mantenimiento de sistemas de diseño exitosos, con Brad Fost

  • Índice
    1. Mecanografía básica
    2. Conjuntos más pequeños
    3. Introduzca genéricos
    4. Escribiendo parámetros
    5. Enlaces genéricos
    6. Tipos condicionales y tipos literales de plantilla recursiva
    7. Tipos estáticos para comportamiento dinámico

    En este artículo, analizamos algunas de las características más avanzadas de TypeScript, como tipos de unión, tipos condicionales, tipos literales de plantilla y genéricos. Queremos formalizar el comportamiento más dinámico de JavaScript de manera que podamos detectar la mayoría de los errores antes de que ocurran. Aplicamos varios aprendizajes de todos los capítulos de TypeScript en 50 lecciones , un libro que publicamos aquí en Smashing Magazine a fines de 2020. Si está interesado en aprender más, ¡asegúrese de consultarlo!

     

    JavaScript es un lenguaje de programación inherentemente dinámico. Nosotros, como desarrolladores, podemos expresar mucho con poco esfuerzo, y el lenguaje y su tiempo de ejecución determinan lo que pretendemos hacer. ¡Esto es lo que hace que JavaScript sea tan popular entre los principiantes y lo que hace que los desarrolladores experimentados sean productivos! Sin embargo, hay una advertencia: ¡debemos estar alerta! Errores, errores tipográficos, comportamiento correcto del programa: ¡mucho de eso sucede en nuestra cabeza!

    Eche un vistazo al siguiente ejemplo.

    app.get("/api/users/:userID", function(req, res) { if (req.method === "POST") { res.status(20).send({ message: "Got you, user " + req.params.userId }); }})

    Tenemos un servidor estilo https://expressjs.com/ que nos permite definir una ruta (o ruta) y ejecuta una devolución de llamada si se solicita la URL.

     

    La devolución de llamada toma dos argumentos:

    1. El requestobjeto.
      Aquí obtenemos información sobre el método HTTP utilizado (por ejemplo, GET, POST, PUT, DELETE) y parámetros adicionales que entran. En este ejemplo, userIDse debe asignar a un parámetro userIDque, bueno, contenga el ID del usuario.
    2. El objeto responseu reply.
      Aquí queremos preparar una respuesta adecuada del servidor al cliente. Queremos enviar códigos de estado correctos (método status) y enviar salida JSON por cable.

    Lo que vemos en este ejemplo está muy simplificado, pero da una buena idea de lo que estamos haciendo. ¡El ejemplo anterior también está plagado de errores! Echar un vistazo:

    app.get("/api/users/:userID", function(req, res) { if (req.method === "POST") { /* Error 1 */ res.status(20).send({ /* Error 2 */ message: "Welcome, user " + req.params.userId /* Error 3 */ }); }})

    ¡Oh, vaya! ¿Tres líneas de código de implementación y tres errores? ¿Lo que ha sucedido?

    1. El primer error tiene matices. Si bien le decimos a nuestra aplicación que queremos escuchar solicitudes GETapp.get (por lo tanto ), solo hacemos algo si el método de solicitud es POST . En este punto particular de nuestra aplicación, req.methodno se puede POST . Por lo tanto, nunca enviaríamos ninguna respuesta, lo que podría provocar tiempos de espera inesperados.
    2. ¡Genial que enviemos explícitamente un código de estado! 20Sin embargo, no es un código de estado válido. Es posible que los clientes no entiendan lo que está sucediendo aquí.
    3. Esta es la respuesta que queremos enviar. Accedemos a los argumentos analizados pero tenemos un error tipográfico grave. Que userIDno es userId. Todos nuestros usuarios serán recibidos con un "¡Bienvenido, usuario indefinido!". ¡Algo que definitivamente has visto en la naturaleza!

    ¡Y cosas así suceden! Especialmente en JavaScript. Ganamos expresividad (nunca tuvimos que preocuparnos por los tipos), pero tenemos que prestar mucha atención a lo que estamos haciendo.

    Aquí también es donde JavaScript recibe muchas reacciones negativas por parte de los programadores que no están acostumbrados a los lenguajes de programación dinámicos. Por lo general, tienen compiladores que les señalan posibles problemas y detectan errores por adelantado. Es posible que parezcan presumidos cuando desaprueban la cantidad de trabajo adicional que tienes que hacer en tu cabeza para asegurarte de que todo funcione bien. Incluso podrían decirte que JavaScript no tiene tipos. Lo cual no es cierto.

    Anders Hejlsberg, el arquitecto principal de TypeScript, dijo en su discurso de apertura de MS Build 2017 que “ no es que JavaScript no tenga un sistema de tipos. Simplemente no hay manera de formalizarlo ”.

    Y este es el objetivo principal de TypeScript. TypeScript quiere comprender su código JavaScript mejor que usted. Y cuando TypeScript no pueda entender lo que quiere decir, puede ayudar proporcionando información de tipo adicional.

     

    Mecanografía básica

    Y esto es lo que vamos a hacer ahora. Tomemos el getmétodo de nuestro servidor estilo Express y agreguemos suficiente información de tipo para poder excluir tantas categorías de errores como sea posible.

    Comenzamos con información de tipo básico. Tenemos un appobjeto que apunta a una getfunción. La getfunción toma path, que es una cadena, y una devolución de llamada.

    const app = { get, /* post, put, delete, ... to come! */};function get(path: string, callback: CallbackFn) { // to be implemented -- not important right now}

    Si bien stringes un tipo básico, llamado primitivo , CallbackFnes un tipo compuesto que tenemos que definir explícitamente.

    CallbackFnes un tipo de función que toma dos argumentos:

    • req, que es de tipoServerRequest
    • replyque es de tipoServerReply

    CallbackFndevoluciones void.

    type CallbackFn = (req: ServerRequest, reply: ServerReply) = void;

    ServerRequestes un objeto bastante complejo en la mayoría de los marcos. Hacemos una versión simplificada con fines de demostración. Pasamos una methodcadena, for "GET", "POST", "PUT", "DELETE", etc. También tiene un paramsregistro. Los registros son objetos que asocian un conjunto de claves con un conjunto de propiedades. Por ahora, queremos permitir que cada stringclave se asigne a una stringpropiedad. Refactorizamos este más tarde.

    type ServerRequest = { method: string; params: Recordstring, string;};

    Para ServerReply, presentamos algunas funciones, sabiendo que un ServerReplyobjeto real tiene muchas más. Una sendfunción toma un argumento opcional con los datos que queremos enviar. Y tenemos la posibilidad de establecer un código de estado con la statusfunción.

    type ServerReply = { send: (obj?: any) = void; status: (statusCode: number) = ServerReply;};

    Eso ya es algo, y podemos descartar un par de errores:

    app.get("/api/users/:userID", function(req, res) { if(req.method === 2) {// ^^^^^^^^^^^^^^^^^ Error, type number is not assignable to string res.status("200").send()// ^^^^^ Error, type string is not assignable to number }})

    Pero aún podemos enviar códigos de estado incorrectos (cualquier número es posible) y no tener idea de los posibles métodos HTTP (cualquier cadena es posible). Refinamos nuestros tipos.

     

    Conjuntos más pequeños

    Puede ver los tipos primitivos como un conjunto de todos los valores posibles de esa categoría determinada. Por ejemplo, stringincluye todas las cadenas posibles que se pueden expresar en JavaScript, numberincluye todos los números posibles con precisión de doble flotante. booleanincluye todos los valores booleanos posibles, que son truey false.

    TypeScript le permite refinar esos conjuntos a subconjuntos más pequeños. Por ejemplo, podemos crear un tipo Methodque incluya todas las cadenas posibles que podemos recibir para los métodos HTTP:

    type Methods= "GET" | "POST" | "PUT" | "DELETE";type ServerRequest = { method: Methods; params: Recordstring, string;};

    Methodes un conjunto más pequeño del stringconjunto más grande. Methodes un tipo de unión de tipos literales. Un tipo literal es la unidad más pequeña de un conjunto dado. Una cadena literal. Un número literal. No hay ambigüedad. Es solo "GET". Los colocas en una unión con otros tipos literales, creando un subconjunto de los tipos más grandes que tengas. También puede crear un subconjunto con tipos literales de ambos stringy number, o diferentes tipos de objetos compuestos. Hay muchas posibilidades para combinar y unir tipos literales.

    Esto tiene un efecto inmediato en la devolución de llamada de nuestro servidor. De repente, podemos diferenciar entre esos cuatro métodos (o más si es necesario) y podemos agotar todas las posibilidades en el código. TypeScript nos guiará:

    app.get("/api/users/:userID", function (req, res) { // at this point, TypeScript knows that req.method // can take one of four possible values switch (req.method) { case "GET": break; case "POST": break; case "DELETE": break; case "PUT": break; default: // here, req.method is never req.method; }});

    Con cada casedeclaración que haga, TypeScript puede brindarle información sobre las opciones disponibles. Pruébelo usted mismo . Si agotó todas las opciones, TypeScript le dirá en su defaultsucursal que esto puede neversuceder. Este es literalmente el tipo never, lo que significa que posiblemente haya alcanzado un estado de error que necesita manejar.

    Esa es una categoría de errores menos. Ahora sabemos exactamente qué posibles métodos HTTP están disponibles.

    Podemos hacer lo mismo con los códigos de estado HTTP, definiendo un subconjunto de números válidos que statusCodepueden tomar:

    type StatusCode = 100 | 101 | 102 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 226 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 444 | 449 | 450 | 451 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 598 | 599;type ServerReply = { send: (obj?: any) = void; status: (statusCode: StatusCode) = ServerReply;};

    El tipo StatusCodees nuevamente un tipo de unión. Y con esto excluimos otra categoría de errores. De repente, un código como ese falla:

     

    app.get("/api/user/:userID", (req, res) = { if(req.method === "POS") {// ^^^^^^^^^^^^^^^^^^^ 'Methods' and '"POS"' have no overlap. res.status(20)// ^^ '20' is not assignable to parameter of type 'StatusCode' }})

    ¡Y nuestro software se vuelve mucho más seguro! ¡Pero podemos hacer más!

    Introduzca genéricos

    Cuando definimos una ruta con app.get, implícitamente sabemos que el único método HTTP posible es "GET". Pero con nuestras definiciones de tipos, todavía tenemos que verificar todas las partes posibles de la unión.

    El tipo for CallbackFnes correcto, ya que podríamos definir funciones de devolución de llamada para todos los métodos HTTP posibles, pero si llamamos explícitamente a app.get, sería bueno ahorrar algunos pasos adicionales que solo son necesarios para cumplir con los tipos.

    ¡Los genéricos de TypeScript pueden ayudar! Los genéricos son una de las características principales de TypeScript que le permiten obtener el comportamiento más dinámico de los tipos estáticos. En TypeScript en 50 lecciones , dedicamos los últimos tres capítulos a profundizar en todas las complejidades de los genéricos y su funcionalidad única.

    Lo que necesita saber ahora es que queremos definir ServerRequestde manera que podamos especificar una parte Methodsen lugar de todo el conjunto. Para eso usamos la sintaxis genérica donde podemos definir parámetros como lo haríamos con las funciones:

    type ServerRequestMet extends Methods = { method: Met; params: Recordstring, string;};

    Esto es lo que pasa:

    1. ServerRequestse convierte en un tipo genérico, como lo indican los corchetes angulares
    2. Definimos un parámetro genérico llamado Met, que es un subconjunto de tipoMethods
    3. Usamos este parámetro genérico como variable genérica para definir el método.

    También te recomiendo que consultes mi artículo sobre cómo nombrar parámetros genéricos .

    Con ese cambio, podemos especificar diferentes ServerRequestmensajes sin duplicar cosas:

    type OnlyGET = ServerRequest"GET";type OnlyPOST = ServerRequest"POST";type POSTorPUT = ServerRquest"POST" | "PUT";

    Dado que cambiamos la interfaz de ServerRequest, tenemos que realizar cambios en todos los demás tipos que usan ServerRequest, me gusta CallbackFny la getfunción:

    type CallbackFnMet extends Methods = ( req: ServerRequestMet, reply: ServerReply) = void;function get(path: string, callback: CallbackFn"GET") { // to be implemented}

    Con la getfunción, pasamos un argumento real a nuestro tipo genérico. Sabemos que no será solo un subconjunto de Methods, sabemos exactamente con qué subconjunto estamos tratando.

    Ahora, cuando usamos app.get, solo tenemos un valor posible para req.method:

    app.get("/api/users/:userID", function (req, res) { req.method; // can only be get});

    Esto garantiza que no asumimos que métodos HTTP similares "POST"o similares estén disponibles cuando creamos una app.getdevolución de llamada. Sabemos exactamente a qué nos enfrentamos en este momento, así que reflejémoslo en nuestros tipos.

     

    Ya hicimos mucho para asegurarnos de que request.methodesté escrito de manera razonable y represente el estado real de las cosas. Un buen beneficio que obtenemos al subconjunto del Methodstipo de unión es que podemos crear una función de devolución de llamada de propósito general fuera de app.getla que sea segura para tipos:

    const handler: CallbackFn"PUT" | "POST" = function(res, req) { res.method // can be "POST" or "PUT"};const handlerForAllMethods: CallbackFnMethods = function(res, req) { res.method // can be all methods};app.get("/api", handler);// ^^^^^^^ Nope, we don’t handle "GET"app.get("/api", handlerForAllMethods); // This works

    Escribiendo parámetros

    Lo que no hemos tocado todavía es escribir el paramsobjeto. Hasta ahora, obtenemos un registro que permite acceder a todas stringlas claves. ¡Nuestra tarea ahora es hacerlo un poco más específico!

    Lo hacemos agregando otra variable genérica. Uno para los métodos, otro para las posibles claves en nuestro Record:

    type ServerRequestMet extends Methods, Par extends string = string = { method: Met; params: RecordPar, string;};

    La variable de tipo genérico Parpuede ser un subconjunto de tipo stringy el valor predeterminado es cada cadena. Con eso, podemos saber ServerRequestqué claves esperamos:

    // request.method = "GET"// request.params = {// userID: string// }type WithUserID = ServerRequest"GET", "userID"

    Agreguemos el nuevo argumento a nuestra getfunción y el CallbackFntipo, para que podamos configurar los parámetros solicitados:

    function getPar extends string = string( path: string, callback: CallbackFn"GET", Par) { // to be implemented}type CallbackFnMet extends Methods, Par extends string = ( req: ServerRequestMet, Par, reply: ServerReply) = void;

    Si no lo configuramos Parexplícitamente, el tipo funciona como estamos acostumbrados, ya que Parel valor predeterminado es string. Sin embargo, si lo configuramos, ¡de repente tendremos una definición adecuada para el req.paramsobjeto!

    app.get"userID"("/api/users/:userID", function (req, res) { req.params.userID; // Works!! req.params.anythingElse; // doesn’t work!!});

    ¡Genial! Aunque hay una pequeña cosa que se puede mejorar. Todavía podemos pasar cada cadena al pathargumento de app.get. ¿No sería mejor si pudiéramos reflexionar Parallí también?

    ¡Podemos! Con el lanzamiento de la versión 4.1, TypeScript puede crear tipos literales de plantilla . Sintácticamente, funcionan igual que los literales de plantilla de cadena, pero a nivel de tipo. Mientras pudimos dividir el conjunto stringen subconjuntos con tipos literales de cadena (como lo hicimos con Métodos), los tipos literales de plantilla nos permiten incluir un espectro completo de cadenas.

     

    Creemos un tipo llamado IncludesRouteParams, donde queremos asegurarnos de que Paresté incluido correctamente en la forma estilo Express de agregar dos puntos delante del nombre del parámetro:

    type IncludesRouteParamsPar extends string = | `${string}/:${Par}` | `${string}/:${Par}/${string}`;

    El tipo genérico IncludesRouteParamstoma un argumento, que es un subconjunto de string. Crea un tipo de unión de dos literales de plantilla:

    1. El primer literal de plantilla comienza con cualquiera string y luego incluye un /carácter seguido de un :carácter, seguido del nombre del parámetro. Esto asegura que detectemos todos los casos en los que el parámetro está al final de la cadena de ruta.
    2. El segundo literal de plantilla comienza con any string , seguido del mismo patrón de /y :el nombre del parámetro. Luego tenemos otro /carácter, seguido de cualquier cadena. Esta rama del tipo unión asegura que detectemos todos los casos en los que el parámetro se encuentra en algún lugar dentro de una ruta.

    Así es como se comporta IncludesRouteParamsel nombre del parámetro userIDcon diferentes casos de prueba:

    const a: IncludeRouteParams"userID" = "/api/user/:userID" // const a: IncludeRouteParams"userID" = "/api/user/:userID/orders" // const a: IncludeRouteParams"userID" = "/api/user/:userId" // const a: IncludeRouteParams"userID" = "/api/user" // const a: IncludeRouteParams"userID" = "/api/user/:userIDAndmore" // 

    Incluyamos nuestro nuevo tipo de utilidad en la getdeclaración de función.

    function getPar extends string = string( path: IncludesRouteParamsPar, callback: CallbackFn"GET", Par) { // to be implemented}app.get"userID"( "/api/users/:userID", function (req, res) { req.params.userID; // YEAH! });

    ¡Excelente! ¡Tenemos otro mecanismo de seguridad para garantizar que no nos perdamos de agregar los parámetros a la ruta real! Qué poderoso.

    Enlaces genéricos

    Pero adivina qué, todavía no estoy contento con eso. Hay algunos problemas con ese enfoque que se vuelven evidentes en el momento en que sus rutas se vuelven un poco más complejas.

    1. El primer problema que tengo es que necesitamos indicar explícitamente nuestros parámetros en el parámetro de tipo genérico. Tenemos que vincularnos Para "userID", aunque lo especificaríamos de todos modos en el argumento de ruta de la función. ¡Esto no es JavaScript!
    2. Este enfoque solo maneja un parámetro de ruta. En el momento en que agregamos una unión, por ejemplo, "userID" | "orderId"la verificación de seguridad se cumple con solo uno de esos argumentos disponible. Así funcionan los decorados. Puede ser uno o el otro.

    Debe haber una mejor manera. Y ahí está. De lo contrario, este artículo terminaría con una nota muy amarga.

    ¡Inviertamos el orden! No intentemos definir los parámetros de ruta en una variable de tipo genérico, sino más bien extraer las variables de las que pathpasamos como primer argumento de app.get.

     

    Para llegar al valor real, tenemos que ver cómo funciona el enlace genérico en TypeScript. Tomemos esta identityfunción por ejemplo:

    function identityT(inp: T) : T { return inp}

    Puede que sea la función genérica más aburrida que jamás hayas visto, pero ilustra perfectamente un punto. identitytoma un argumento y devuelve la misma entrada nuevamente. El tipo es el tipo genérico Ty también devuelve el mismo tipo.

    Ahora podemos vincularnos Ta string, por ejemplo:

    const z = identitystring("yes"); // z is of type string

    Este enlace explícitamente genérico garantiza que solo pasemos stringsa identityy, dado que enlazamos explícitamente, el tipo de retorno también es string. Si nos olvidamos de enlazar, sucede algo interesante:

    const y = identity("yes") // y is of type "yes"

    En ese caso, TypeScript infiere el tipo a partir del argumento que pasa y lo vincula Tal tipo literal de cadena "yes" . Esta es una excelente manera de convertir un argumento de función a un tipo literal, que luego usamos en nuestros otros tipos genéricos.

    Hagámoslo adaptándonos app.get.

    function getPath extends string = string( path: Path, callback: CallbackFn"GET", ParseRouteParamsPath) { // to be implemented}

    Eliminamos el Partipo genérico y añadimos Path. Pathpuede ser un subconjunto de cualquiera string. Lo configuramos pathen este tipo genérico Path, lo que significa que en el momento en que le pasamos un parámetro get, capturamos su tipo literal de cadena. Pasamos Patha un nuevo tipo genérico ParseRouteParamsque aún no hemos creado.

    Trabajemos en ParseRouteParams. Aquí, volvemos a cambiar el orden de los eventos. En lugar de pasar los parámetros de ruta solicitados al genérico para asegurarnos de que la ruta esté bien, pasamos la ruta de ruta y extraemos los posibles parámetros de ruta. Para eso, necesitamos crear un tipo condicional.

    Tipos condicionales y tipos literales de plantilla recursiva

    Los tipos condicionales son sintácticamente similares al operador ternario en JavaScript. Verifica una condición y, si se cumple, devuelve la rama A; de lo contrario, devuelve la rama B. Por ejemplo:

    type ParseRouteParamsRte = Rte extends `${string}/:${infer P}` ? P : never;

    Aquí, verificamos si Rtehay un subconjunto de cada ruta que termina con el parámetro al final Estilo Express (con un precedente "/:"). Si es así, inferimos esta cadena. Lo que significa que capturamos su contenido en una nueva variable. Si se cumple la condición, devolvemos la cadena recién extraída; de lo contrario, devolvemos nunca, como en: "No hay parámetros de ruta".

    Si lo probamos, obtenemos algo como esto:

    type Params = ParseRouteParams"/api/user/:userID" // Params is "userID"type NoParams = ParseRouteParams"/api/user" // NoParams is never -- no params!

    Genial, eso ya es mucho mejor que lo que hicimos antes. Ahora queremos capturar todos los demás parámetros posibles. Para eso tenemos que agregar otra condición:

     

    type ParseRouteParamsRte = Rte extends `${string}/:${infer P}/${infer Rest}` ? P | ParseRouteParams`/${Rest}` : Rte extends `${string}/:${infer P}` ? P : never;

    Nuestro tipo condicional funciona ahora de la siguiente manera:

    1. En la primera condición, verificamos si hay un parámetro de ruta en algún lugar entre la ruta. Si es así, extraemos tanto el parámetro de ruta como todo lo que viene después. Devolvemos el parámetro de ruta recién encontrado Pen una unión donde llamamos al mismo tipo genérico de forma recursiva con el archivo Rest. Por ejemplo, si pasamos la ruta "/api/users/:userID/orders/:orderID"a ParseRouteParams, inferimos "userID"hacia Py "orders/:orderID"hacia Rest. Llamamos al mismo tipo conRest
    2. Aquí es donde entra en juego la segunda condición. Aquí comprobamos si hay un tipo al final. Este es el caso de "orders/:orderID". Extraemos "orderID"y devolvemos este tipo literal.
    3. Si no queda más parámetro de ruta, regresamos nunca.

    Dan Vanderkam muestra un tipo similar y más elaborado para ParseRouteParams, pero el que ves arriba también debería funcionar. Si probamos nuestro recién adaptado ParseRouteParams, obtenemos algo como esto:

    // Params is "userID"type Params = ParseRouteParams"/api/user/:userID"// MoreParams is "userID" | "orderID"type MoreParams = ParseRouteParams"/api/user/:userID/orders/:orderId"

    Apliquemos este nuevo tipo y veamos cómo app.getse ve nuestro uso final.

    app.get("/api/users/:userID/orders/:orderID", function (req, res) { req.params.userID; // YES!! req.params.orderID; // Also YES!!!});

    Guau. ¡Eso se parece al código JavaScript que teníamos al principio!

    Tipos estáticos para comportamiento dinámico

    Los tipos que acabamos de crear para una función app.getaseguran que excluimos un montón de posibles errores:

    1. Sólo podemos pasar códigos de estado numéricos adecuados ares.status()
    2. req.methodes una de las cuatro cadenas posibles, y cuando usamos app.get, sabemos que solo será"GET"
    3. Podemos analizar los parámetros de ruta y asegurarnos de que no tengamos ningún error tipográfico dentro de nuestra devolución de llamada.

    Si miramos el ejemplo del principio de este artículo, obtenemos los siguientes mensajes de error:

    app.get("/api/users/:userID", function(req, res) { if (req.method === "POST") {// ^^^^^^^^^^^^^^^^^^^^^// This condition will always return 'false'// since the types '"GET"' and '"POST"' have no overlap. res.status(20).send({// ^^// Argument of type '20' is not assignable to// parameter of type 'StatusCode' message: "Welcome, user " + req.params.userId// ^^^^^^// Property 'userId' does not exist on type// '{ userID: string; }'. Did you mean 'userID'? }); }})

    ¡Y todo eso antes de ejecutar nuestro código! Los servidores estilo Express son un ejemplo perfecto de la naturaleza dinámica de JavaScript. Dependiendo del método que llame, la cadena que pase como primer argumento, muchos cambios de comportamiento dentro de la devolución de llamada. Tome otro ejemplo y todos sus tipos se verán completamente diferentes.

    Pero con algunos tipos bien definidos, podemos captar este comportamiento dinámico mientras editamos nuestro código. ¡En tiempo de compilación con tipos estáticos, no en tiempo de ejecución cuando las cosas van bien!

    Y este es el poder de TypeScript. Un sistema de tipos estáticos que intenta formalizar todo el comportamiento dinámico de JavaScript que todos conocemos tan bien. Si quieres probar el ejemplo que acabamos de crear, dirígete al área de juegos de TypeScript y juguetea con él.


    En este artículo, abordamos muchos conceptos. Si desea saber más, consulte TypeScript en 50 lecciones , donde obtendrá una breve introducción al sistema de tipos en lecciones pequeñas y fácilmente digeribles. Las versiones de libros electrónicos están disponibles de inmediato y el libro impreso será una excelente referencia para su biblioteca de codificación.

    (vf, il)Explora más en

    • Herramientas
    • Codificación
    • javascript
    • Mecanografiado





    Tal vez te puede interesar:

    1. ¿Deberían abrirse los enlaces en ventanas nuevas?
    2. 24 excelentes tutoriales de AJAX
    3. 70 técnicas nuevas y útiles de AJAX y JavaScript
    4. Más de 45 excelentes recursos y repositorios de fragmentos de código

    Escritura estática dinámica en TypeScript

    Mecanografía básicaConjuntos más pequeñosIntroduzca genéricosEscribiendo parámetrosEnlaces genéricosTipos condicionales y tipos literales de plantilla r

    programar

    es

    2025-01-15

     

    Si crees que alguno de los contenidos (texto, imagenes o multimedia) en esta página infringe tus derechos relativos a propiedad intelectual, marcas registradas o cualquier otro de tus derechos, por favor ponte en contacto con nosotros en el mail [email protected] y retiraremos este contenido inmediatamente

     

     

    Update cookies preferences