Logotipo de Zephyrnet

Reaccionar con TypeScript: mejores prácticas

Fecha:

React y TypeScript son dos tecnologías asombrosas utilizadas por muchos desarrolladores en estos días. Saber cómo hacer las cosas puede resultar complicado y, a veces, es difícil encontrar la respuesta correcta. No es para preocuparse. Hemos reunido las mejores prácticas junto con ejemplos para aclarar cualquier duda que pueda tener.

¡Vamos a bucear!

Cómo funcionan juntos React y TypeScript

Antes de comenzar, revisemos cómo funcionan juntos React y TypeScript. React es una "biblioteca JavaScript para crear interfaces de usuario", mientras que TypeScript es un "superconjunto escrito de JavaScript que se compila en JavaScript simple". Al usarlos juntos, esencialmente construimos nuestras IU usando una versión escrita de JavaScript.

La razón por la que podría usarlos juntos sería para obtener los beneficios de un lenguaje escrito estáticamente (TypeScript) para su interfaz de usuario. Esto significa más seguridad y menos errores en el envío a la parte delantera.

¿TypeScript compila mi código React?

Una pregunta común que siempre es buena para revisar es si TypeScript compila su código React. La forma en que funciona TypeScript es similar a esta interacción:

TS: "Oye, ¿este es todo tu código de IU?"
Reaccionar: "¡Sip!"
TS: "¡Frio! Voy a compilarlo y asegurarme de que no te hayas perdido nada ".
Reaccionar: "¡Suena bien para mí!"

Entonces la respuesta es sí, ¡lo hace! Pero luego, cuando cubrimos el tsconfig.json configuración, la mayoría de las veces querrá usar "noEmit": true. Lo que esto significa es TypeScript no emitir JavaScript después de la compilación. Esto se debe a que, por lo general, solo utilizamos TypeScript para realizar nuestra verificación de tipos.

La salida es manejada, en un entorno CRA, por react-scripts. Corremos yarn build y react-scripts agrupa la salida para la producción.

En resumen, TypeScript compila su código de React para verificar su código. No emite ninguna salida de JavaScript (en la mayoría de los escenarios). La salida sigue siendo similar a un proyecto React que no es de TypeScript.

¿Puede TypeScript funcionar con React y webpack?

Sí, TypeScript puede funcionar con React y webpack. Por suerte para ti, el manual oficial de TypeScript tiene una guía en eso.

Con suerte, eso le dará un repaso suave sobre cómo los dos trabajan juntos. ¡Ahora, a las mejores prácticas!

BUENAS PRÁCTICAS

Hemos investigado las preguntas más comunes y hemos reunido esta práctica lista de los casos de uso más comunes para React with TypeScript. De esta manera, puede seguir las mejores prácticas en sus proyectos utilizando este artículo como referencia.

Configuración

Una de las partes del desarrollo menos divertidas, pero más importantes, es la configuración. ¿Cómo podemos configurar las cosas en el menor tiempo posible que proporcionen la máxima eficiencia y productividad? Discutiremos la configuración del proyecto que incluye:

  • tsconfig.json
  • ESLint
  • Más bonita
  • Extensiones y configuraciones de VS Code.

Configuración del proyecto

La forma más rápida de iniciar una aplicación React / TypeScript es usando create-react-app con la plantilla TypeScript. Puede hacer esto ejecutando:

npx create-react-app my-app --template typescript

Esto le dará lo mínimo para comenzar a escribir React con TypeScript. Algunas diferencias notables son:

  • las .tsx extensión de archivo
  • las tsconfig.json
  • las react-app-env.d.ts

La tsx es para "TypeScript JSX". los tsconfig.json es el archivo de configuración de TypeScript, que tiene algunos valores predeterminados. los react-app-env.d.ts hace referencia a los tipos de react-scriptsy ayuda con cosas como permitir las importaciones de SVG.

tsconfig.json

Por suerte para nosotros, la última plantilla de React / TypeScript genera tsconfig.json para nosotros. Sin embargo, agregan lo mínimo para comenzar. Le sugerimos que modifique el suyo para que coincida con el siguiente. También hemos agregado comentarios para explicar el propósito de cada opción:

{ "compilerOptions": { "target": "es5", // Specify ECMAScript target version "lib": [ "dom", "dom.iterable", "esnext" ], // List of library files to be included in the compilation "allowJs": true, // Allow JavaScript files to be compiled "skipLibCheck": true, // Skip type checking of all declaration files "esModuleInterop": true, // Disables namespace imports (import * as fs from "fs") and enables CJS/AMD/UMD style imports (import fs from "fs") "allowSyntheticDefaultImports": true, // Allow default imports from modules with no default export "strict": true, // Enable all strict type checking options "forceConsistentCasingInFileNames": true, // Disallow inconsistently-cased references to the same file. "module": "esnext", // Specify module code generation "moduleResolution": "node", // Resolve modules using Node.js style "resolveJsonModule": true, // Include modules imported with .json extension "noEmit": true, // Do not emit output (meaning do not compile code, only perform type checking) "jsx": "react" // Support JSX in .tsx files "sourceMap": true, // Generate corrresponding .map file "declaration": true, // Generate corresponding .d.ts file "noUnusedLocals": true, // Report errors on unused locals "noUnusedParameters": true, // Report errors on unused parameters "experimentalDecorators": true, // Enables experimental support for ES decorators "incremental": true, // Enable incremental compilation by reading/writing information from prior compilations to a file on disk "noFallthroughCasesInSwitch": true // Report errors for fallthrough cases in switch statement }, "include": [ "src/**/*" // *** The files TypeScript should type check *** ], "exclude": ["node_modules", "build"] // *** The files to not type check ***
}

Las recomendaciones adicionales provienen del [react-typescript-cheatsheet vibrante e inclusiva y las explicaciones vienen del Documentos de opciones del compilador en el Manual oficial de TypeScript. Este es un recurso maravilloso si desea conocer otras opciones y lo que hacen.

ESLint / Prettier

Para asegurarse de que su código siga las reglas del proyecto o de su equipo, y que el estilo sea consistente, se recomienda que configure ESLint y Prettier. Para que jueguen bien, siga estos pasos para configurarlo.

  1. Instale las dependencias de desarrollo necesarias:

    yarn add eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-react --dev
    
    
  2. Créar un .eslintrc.js archivo en la raíz y agregue lo siguiente:

    module.exports = { parser: '@typescript-eslint/parser', // Specifies the ESLint parser extends: [ 'plugin:react/recommended', // Uses the recommended rules from @eslint-plugin-react 'plugin:@typescript-eslint/recommended', // Uses the recommended rules from @typescript-eslint/eslint-plugin ], parserOptions: { ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features sourceType: 'module', // Allows for the use of imports ecmaFeatures: { jsx: true, // Allows for the parsing of JSX }, }, rules: { // Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs // e.g. "@typescript-eslint/explicit-function-return-type": "off", }, settings: { react: { version: 'detect', // Tells eslint-plugin-react to automatically detect the version of React to use }, },
    };
    
    
  3. Agregue dependencias más bonitas:

    yarn add prettier eslint-config-prettier eslint-plugin-prettier --dev
    
    
  4. Créar un .prettierrc.js archivo en la raíz y agregue lo siguiente:

    module.exports = { semi: true, trailingComma: 'all', singleQuote: true, printWidth: 120, tabWidth: 4,
    };
    
    
  5. Actualizar el .eslintrc.js archivo:

    module.exports = { parser: '@typescript-eslint/parser', // Specifies the ESLint parser extends: [ 'plugin:react/recommended', // Uses the recommended rules from @eslint-plugin-react 'plugin:@typescript-eslint/recommended', // Uses the recommended rules from the @typescript-eslint/eslint-plugin
    + 'prettier/@typescript-eslint', // Uses eslint-config-prettier to disable ESLint rules from @typescript-eslint/eslint-plugin that would conflict with prettier
    + 'plugin:prettier/recommended', // Enables eslint-plugin-prettier and displays prettier errors as ESLint errors. Make sure this is always the last configuration in the extends array. ], parserOptions: { ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features sourceType: 'module', // Allows for the use of imports ecmaFeatures: { jsx: true, // Allows for the parsing of JSX }, }, rules: { // Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs // e.g. "@typescript-eslint/explicit-function-return-type": "off", }, settings: { react: { version: 'detect', // Tells eslint-plugin-react to automatically detect the version of React to use }, },
    };
    
    

Estas recomendaciones provienen de un recurso comunitario escrito llamado "Uso de ESLint y Prettier en un proyecto de TypeScript" por Robert Cooper. Si visita su blog, puede leer más sobre el "por qué" detrás de estas reglas y configuraciones.

Extensiones y configuraciones de VSCode

Hemos agregado ESLint y Prettier y el siguiente paso para mejorar nuestro DX es corregir / embellecer automáticamente nuestro código al guardar.

Primero, instale el Extensión ESLint y del Extensión más bonita para VSCode. Esto permitirá que ESLint se integre sin problemas con su editor.

A continuación, actualice la configuración de su espacio de trabajo agregando lo siguiente a su .vscode/settings.json:

{ "editor.formatOnSave": true
}

Esto permitirá que VS Code haga su magia y arregle su código cuando guarde. ¡Es bonito!

Estas sugerencias también provienen del artículo vinculado anteriormente "Uso de ESLint y Prettier en un proyecto de TypeScript" por Robert Cooper.

Componentes

Uno de los conceptos centrales de React son los componentes. Aquí, nos referiremos a componentes estándar a partir de React v16.8, es decir, aquellos que usan ganchos en lugar de clases.

En general, hay mucho de qué preocuparse por los componentes básicos. Veamos un ejemplo:

import React from 'react' // Written as a function declaration
function Heading(): React.ReactNode { return <h1>My Website Heading</h1>
} // Written as a function expression
const OtherHeading: React.FC = () => <h1>My Website Heading</h1>

Note la diferencia clave aquí. En el primer ejemplo, escribimos nuestra función como declaración de función. Anotamos el tipo de retorno React.Node porque eso es lo que vuelve. En contraste, el segundo ejemplo usa un expresión de función. Debido a que la segunda instancia devuelve una función, en lugar de un valor o expresión, anotamos el tipo de función React.FC para React "Componente de función".

Puede resultar confuso recordar los dos. Es principalmente una cuestión de elección de diseño. Cualquiera que elija utilizar en su proyecto, utilícelo de forma coherente.

Accesorios

El siguiente concepto central que cubriremos son los accesorios. Puede definir sus accesorios utilizando una interfaz o un tipo. Veamos otro ejemplo:

import React from 'react' interface Props { name: string; color: string;
} type OtherProps = { name: string; color: string;
} // Notice here we're using the function declaration with the interface Props
function Heading({ name, color }: Props): React.ReactNode { return <h1>My Website Heading</h1>
} // Notice here we're using the function expression with the type OtherProps
const OtherHeading: React.FC<OtherProps> = ({ name, color }) => <h1>My Website Heading</h1>

Cuando se trata de tipos o interfaces, sugerimos seguir las pautas presentadas por el react-typescript-cheatsheet comunidad:

  • "Utilice siempre la interfaz para la definición de API pública al crear una biblioteca o definiciones de tipo de ambiente de terceros".
  • "Considere usar el tipo para su React Component Props y State, porque es más limitado".

Puede leer más sobre la discusión y ver una práctica tabla que compara tipos e interfaces esta página.

Veamos un ejemplo más para que podamos ver algo un poco más práctico:

import React from 'react' type Props = { /** color to use for the background */ color?: string; /** standard children prop: accepts any valid React Node */ children: React.ReactNode; /** callback function passed to the onClick handler*/ onClick: () => void;
} const Button: React.FC<Props> = ({ children, color = 'tomato', onClick }) => { return <button style={{ backgroundColor: color }} onClick={onClick}>{children}</button>
}

En este <Button /> componente, usamos un tipo para nuestros accesorios. Cada accesorio tiene una breve descripción arriba para proporcionar más contexto a otros desarrolladores. los ? después del accesorio llamado color indica que es opcional. los children prop toma un React.ReactNode porque acepta todo lo que sea un valor de retorno válido de un componente (leer más aquí). Para dar cuenta de nuestro opcional color prop, usamos un valor predeterminado al desestructurarlo. Este ejemplo debería cubrir los conceptos básicos y mostrar que tienes que escribir tipos para tus accesorios y usar valores opcionales y predeterminados.

En general, tenga en cuenta estas cosas al escribir sus accesorios en un proyecto de React y TypeScript:

  • Siempre agregue comentarios descriptivos a sus accesorios usando la notación TSDoc /** comment */.
  • Ya sea que use tipos o interfaces para los accesorios de sus componentes, utilícelos de manera consistente.
  • Cuando los accesorios son opcionales, maneje apropiadamente o use valores predeterminados.

Manos

Afortunadamente, la inferencia de tipo TypeScript funciona bien cuando se utilizan ganchos. Esto significa que no tiene mucho de qué preocuparse. Por ejemplo, tome este ejemplo:

// `value` is inferred as a string
// `setValue` is inferred as (newValue: string) => void
const [value, setValue] = useState('')

TypeScript infiere los valores dados para su uso por useState gancho. Esta es un área donde React y TypeScript simplemente funcionan juntos y es hermoso.

En las raras ocasiones en las que necesita inicializar un gancho con un valor nulo, puede hacer uso de un genérico y pasar una unión para escribir correctamente su gancho. Vea esta instancia:

type User = { email: string; id: string;
} // the generic is the < >
// the union is the User | null
// together, TypeScript knows, "Ah, user can be User or null".
const [user, setUser] = useState<User | null>(null);

El otro lugar donde TypeScript brilla con Hooks es con userReducer, donde puedes aprovechar sindicatos discriminados. Aquí tienes un ejemplo útil:

type AppState = {};
type Action = | { type: "SET_ONE"; payload: string } | { type: "SET_TWO"; payload: number }; export function reducer(state: AppState, action: Action): AppState { switch (action.type) { case "SET_ONE": return { ...state, one: action.payload // `payload` is string }; case "SET_TWO": return { ...state, two: action.payload // `payload` is number }; default: return state; }
}

Fuente: react-typescript-cheatsheet Sección de ganchos

La belleza aquí radica en la utilidad de las uniones discriminadas. Date cuenta cómo Action tiene una unión de dos objetos de aspecto similar. La propiedad type es un literal de cadena. La diferencia entre este y un tipo string es que el valor debe coincidir con el literal cadena definida en el tipo. Esto significa que su programa es más seguro porque un desarrollador solo puede llamar a una acción que tenga un type llave fijada a "SET_ONE" or "SET_TWO".

Como puede ver, los Hooks no agregan mucha complejidad a la naturaleza de un proyecto de React y TypeScript. En todo caso, se prestan bien al dúo.

Casos de uso común

Esta sección cubre los casos de uso más comunes en los que las personas tropiezan al usar TypeScript con React. Esperamos que al compartir esto, evitará las trampas e incluso compartirá este conocimiento con otros.

Manejo de eventos de formulario

Uno de los casos más comunes es escribir correctamente el onChange utilizado en un campo de entrada en un formulario. He aquí un ejemplo:

import React from 'react' const MyInput = () => { const [value, setValue] = React.useState('') // The event type is a "ChangeEvent" // We pass in "HTMLInputElement" to the input function onChange(e: React.ChangeEvent<HTMLInputElement>) { setValue(e.target.value) } return <input value={value} onChange={onChange} id="input-example"/>
}

Ampliación de accesorios de componentes

A veces, desea tomar accesorios de componente declarados para un componente y extenderlos para usarlos en otro componente. Pero es posible que desee modificar uno o dos. Bueno, ¿recuerdas cómo miramos las dos formas de escribir accesorios, tipos o interfaces de componentes? Dependiendo de lo que utilizó, determina cómo extiende los accesorios del componente. Primero veamos la forma en que se usa type:

import React from 'react'; type ButtonProps = { /** the background color of the button */ color: string; /** the text to show inside the button */ text: string;
} type ContainerProps = ButtonProps & { /** the height of the container (value used with 'px') */ height: number;
} const Container: React.FC<ContainerProps> = ({ color, height, width, text }) => { return <div style={{ backgroundColor: color, height: `${height}px` }}>{text}</div>
}

Si declaró sus accesorios usando un interface, entonces podemos usar la palabra clave extends esencialmente "extender" esa interfaz pero hacer una modificación o dos:

import React from 'react'; interface ButtonProps { /** the background color of the button */ color: string; /** the text to show inside the button */ text: string;
} interface ContainerProps extends ButtonProps { /** the height of the container (value used with 'px') */ height: number;
} const Container: React.FC<ContainerProps> = ({ color, height, width, text }) => { return <div style={{ backgroundColor: color, height: `${height}px` }}>{text}</div>
}

Ambos métodos resuelven el problema. Depende de usted decidir cuál usar. Personalmente, extender una interfaz se siente más legible, pero en última instancia, depende de usted y su equipo.

Puede leer más sobre ambos conceptos en el Manual de TypeScript:

Bibliotecas de terceros

Ya sea para un cliente GraphQL como Apollo o para probar con algo como Biblioteca de pruebas de reacción, a menudo nos encontramos usando bibliotecas de terceros en proyectos de React y TypeScript. Cuando esto sucede, lo primero que desea hacer es ver si hay un @types paquete con las definiciones de tipo de TypeScript. Puede hacerlo ejecutando:

#yarn
yarn add @types/<package-name> #npm
npm install @types/<package-name>

Por ejemplo, si está usando Broma, puede hacer esto ejecutando:

#yarn
yarn add @types/jest #npm
npm install @types/jest

Esto le brindaría seguridad de tipo adicional cada vez que utilice Jest en su proyecto.

La @types el espacio de nombres está reservado para las definiciones de tipo de paquete. Viven en un repositorio llamado Definitivamente escrito, que es mantenido parcialmente por el equipo de TypeScript y parcialmente por la comunidad.

¿Deberían guardarse como dependencies or devDependencies en mi package.json?

La respuesta corta es "depende". La mayoría de las veces, pueden hundirse devDependencies si está creando una aplicación web. Sin embargo, si está escribiendo una biblioteca React en TypeScript, es posible que desee incluirlas como dependencies.

Hay algunas respuestas a esto en desbordamiento de pila, que puede consultar para obtener más información.

¿Qué pasa si no tienen un paquete @types?

Si no encuentra un @types package en npm, entonces básicamente tiene dos opciones:

  1. Agregar un archivo de declaración básico
  2. Agregar un archivo de declaración completo

La primera opción significa que crea un archivo basado en el nombre del paquete y lo coloca en la raíz. Si, por ejemplo, necesitáramos tipos para nuestro paquete banana-js, entonces podríamos crear un archivo de declaración básico llamado banana-js.d.ts en la raiz:

declare module 'banana-js';

Esto no le proporcionará seguridad al escribir, pero lo desbloqueará.

Un archivo de declaración más completo sería donde agrega tipos para la biblioteca / paquete:

declare namespace bananaJs { function getBanana(): string; function addBanana(n: number) void; function removeBanana(n: number) void;
}

Si nunca ha escrito un archivo de declaración, le sugerimos que eche un vistazo a la guía en el manual oficial de TypeScript.

Resumen

Usar React y TypeScript juntos de la mejor manera requiere un poco de aprendizaje debido a la cantidad de información, pero los beneficios se amortizan enormemente a largo plazo. En este artículo, cubrimos la configuración, los componentes, los accesorios, los ganchos, los casos de uso comunes y las bibliotecas de terceros. Aunque podríamos profundizar en muchas áreas individuales, esto debería cubrir el 80% necesario para ayudarlo a seguir las mejores prácticas.

Si desea ver esto en acción, puede ver este ejemplo en GitHub.

Si desea ponerse en contacto, compartir otras prácticas recomendadas o conversar sobre el uso conjunto de las dos tecnologías, puede comunicarse conmigo en Twitter. @jsjoeio.

OTRAS LECTURAS

Si desea profundizar, aquí hay algunos recursos que sugerimos:

react-mecanografiado-cheatsheet

Muchas de estas recomendaciones provienen directamente del react-mecanografiado-cheatsheet. Si está buscando ejemplos específicos o detalles sobre cualquier React-TypeScript, este es el lugar para ir. ¡También damos la bienvenida a las contribuciones!

Manual oficial de TypeScript

Otro recurso fantástico es el Manual de TypeScript. Esto se mantiene actualizado por el equipo de TypeScript y proporciona ejemplos y una explicación en profundidad detrás del funcionamiento interno del lenguaje.

Zona de juegos de TypeScript

¿Sabías que puedes probar React con código TypeScript directamente en el navegador? Todo lo que tienes que hacer es importar React. Aquí está un enlace para empezar.

Formas prácticas de avanzar sus habilidades de TypeScript

Lee nuestra guía sobre formas prácticas de mejorar sus habilidades con TypeScript para prepararse para el aprendizaje continuo a medida que avanza.

Fuente: https://www.sitepoint.com/react-with-typescript-best-practices/?utm_source=rss

punto_img

Información más reciente

punto_img