From e8b8beb04acf762f2566f5ed29002a30c939cbb1 Mon Sep 17 00:00:00 2001 From: Dante Calderon Date: Sun, 19 Jan 2020 01:19:01 -0500 Subject: [PATCH 1/2] Update migrating with new changes of original repo --- MIGRANDO.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MIGRANDO.md b/MIGRANDO.md index 831e981..f963f7a 100644 --- a/MIGRANDO.md +++ b/MIGRANDO.md @@ -228,6 +228,7 @@ Contenido antiguo que posiblemente esté desactualizado - [Google](http://neugierig.org/software/blog/2018/09/typescript-at-google.html) - [Tiny][tiny] - [Talk from ForwardJS here](https://www.slideshare.net/tiny/porting-100k-lines-of-code-to-typescript) - [Slack](https://slack.engineering/typescript-at-slack-a81307fa288d) ([podcast](https://softwareengineeringdaily.com/2017/08/11/typescript-at-slack-with-felix-rieseberg/)) +- [Historia de adopción de Netflix](https://www.youtube.com/watch?v=p5Hwb1YbNMY&feature=share) - [Priceline](https://medium.com/priceline-labs/trying-out-typescript-part-1-15a5267215b9) - Dropbox - [Talk at React Loop](https://www.youtube.com/watch?v=veXkJq0Z2Qk) @@ -241,6 +242,7 @@ Código abierto - [React Native CLI](https://github.com/react-native-community/cli/issues/683) - [Next.js](https://nextjs.org/blog/next-9) - [Redux](https://github.com/reduxjs/redux/pull/3536) +- [Dojo 1 -> 2 migration](https://devchat.tv/js-jabber/jsj-277-dojo-2-dylan-schiemann-kitson-kelly/) ## Enlaces From b6979888ad226706f73fa321a04b6c998f75f4f2 Mon Sep 17 00:00:00 2001 From: Dante Calderon Date: Tue, 21 Jan 2020 00:08:29 -0500 Subject: [PATCH 2/2] Up to date ADVANCED and move Linting to README --- AVANZADO.md | 232 ++++---- IGNORATE.md | 1462 +++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 101 ++++ 3 files changed, 1692 insertions(+), 103 deletions(-) create mode 100644 IGNORATE.md diff --git a/AVANZADO.md b/AVANZADO.md index 71173f2..332c6d4 100644 --- a/AVANZADO.md +++ b/AVANZADO.md @@ -71,20 +71,22 @@ La mejor herramienta para crear bibliotecas React + TS en este momento es [`tsdx - [TypeScript 3.2](#typescript-32) - [TypeScript 3.3](#typescript-33) - [TypeScript 3.4](#typescript-34) + - [TypeScript 3.5](#typescript-35) + - [TypeScript 3.6](#typescript-36) + - [TypeScript 3.7](#typescript-37) - [Sección 3: Misceláneas](#sección-3-Misceláneas) - - [Escribir bibliotecas de TypeScript en lugar de aplicaciones](#escribir-bibliotecas-de-typeScript-en-lugar-de-aplicaciones) - [Componentes Comentados](#componentes-comentados) - [Componentes Namespaced](#componentes-namespaced) - [Desarrollo de Sistemas de Diseño](#desarrollo-de-sistemas-de-diseño) - [Migrando desde Flow](#migrando-desde-flow) - [Prettier](#prettier) + - [Testing](#testing) - [Linting](#linting) - [Trabajar con bibliotecas que no son de TypeScript (escribe tu propio index.d.ts)](#trabajar-con-bibliotecas-que-no-son-de-typeScript-escribe-tu-propio-indexdts) - [Sección 4: @types/react y @types/react-dom APIs](#sección-4-typesreact-y-typesreact-dom-apis) - [Agregando atributos no estandarizados](#agregando-atributos-no-estandarizados) - [@types/react-dom](#types-react-dom) - # Sección 0: Tipos de utilidad @@ -699,7 +701,8 @@ Como puede ver en el ejemplo anterior de Omitir, también puede escribir una ló _(Contribuido por [@ferdaber](https://github.com/typescript-cheatsheets/react-typescript-cheatsheet/issues/63))_ -Hay muchos lugares donde desea reutilizar algunas piesas de props debido a _props drilling_, para que pueda exportar el tipo de accesorios como parte del módulo o extraerlos (de cualquier manera funciona). +Hay muchos lugares donde desea reutilizar algunas piesas de props debido a _props drilling_, +para que pueda exportar el tipo de accesorios como parte del módulo o extraerlos (de cualquier manera funciona). La ventaja de extraer los tipos de props es que no necesitas exportar todo. Y el componente fuente se propagará a todos los componentes consumidores. @@ -756,8 +759,7 @@ class DateIsInFutureError extends RangeError {} function parse(date: string) { if (!isValid(date)) throw new InvalidDateFormatError("no es un formato de fecha válido"); - if (isInFuture(date)) - throw new DateIsInFutureError("la fecha es en el futuro"); + if (isInFuture(date)) throw new DateIsInFutureError("la fecha es en el futuro"); // ... } @@ -784,8 +786,7 @@ function parse( ): Date | InvalidDateFormatError | DateIsInFutureError { if (!isValid(date)) return new InvalidDateFormatError("no es un formato de fecha válido"); - if (isInFuture(date)) - return new DateIsInFutureError("la fecha es en el futuro"); + if (isInFuture(date)) return new DateIsInFutureError("la fecha es en el futuro"); // ... } @@ -893,6 +894,22 @@ Ayuda a escribir / usar componentes genéricos: Más información: https://github.com/basarat/typescript-book/blob/master/docs/jsx/react.md#react-jsx-tip-generic-components +## TypeScript 3.0 + +[[Notas de la versión](https://github.com/Microsoft/TypeScript/releases/tag/v3.0.1) | [Publicación del blog](https://blogs.msdn.microsoft.com/typescript/2018/07/30/announcing-typescript-3-0/)] + +1. Parametros rest con tipo para escribir argumentos de longitud variable: + +```ts +// `rest` acepta cualquier numero de strings - incluso ninguno! +function foo(...rest: string[]) { + // ... +} + +foo("hello"); // funciona +foo("hello", "world"); // también funciona +``` + 2. Soporte para `propTypes` y`static defaultProps` en JSX usando `LibraryManagedAttributes`: ```tsx @@ -1070,10 +1087,106 @@ const GenericComponent2 = myHoc(GenericComponent); Consulte también [Notas de la actualización de Google a 3.5](https://github.com/microsoft/TypeScript/issues/33272) -## TypeScript Roadmap +## TypeScript 3.6 + +[[Notas de la versión](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-6.html) | [Publicación del blog](https://devblogs.microsoft.com/typescript/announcing-typescript-3-6/)] + +Nada es particularmente específico de React, pero [el playground](https://github.com/agentcooper/typescript-play) recibió una actualización y [Las clases Ambientales y Funciones pueden fusionarse](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-6.html#ambient-classes-and-functions-can-merge) + +## TypeScript 3.7 + +[[Notas de la versión](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html) | [Publicación del blog](https://devblogs.microsoft.com/typescript/announcing-typescript-3-7/)] + +1. Optional Chaining + +```ts +let x = foo?.bar.baz(); + +// es equivalente a + +let x = foo === null || foo === undefined ? undefined : foo.bar.baz(); + +// Optional Element access +function tryGetFirstElement(arr?: T[]) { + return arr?.[0]; +} + +// Llamada opcional +async function makeRequest(url: string, log?: (msg: string) => void) { + log?.(`Request started at ${new Date().toISOString()}`); + const result = (await fetch(url)).json(); + log?.(`Request finished at at ${new Date().toISOString()}`); + return result; +} +``` + +2. Fusión nula + +```ts +let x = foo ?? bar(); + +// es equivalente a + +let x = foo !== null && foo !== undefined ? foo : bar(); +``` + +**POR LO GENERAL DEBES USAR `??` SIEMPRE QUE USAS NORMALMENTE `||`** a menos que realmente te refieras a falsedad: + +```tsx +function ShowNumber({ value }: { value: number }) { + let _value = value || 0.5; // reemplazará 0 con 0.5 incluso si el usuario se refiere a 0 + // etc... +} +``` + +3. Funciones de Aserción + +```tsx +function assert(condition: any, msg?: string): asserts condition { + if (!condition) { + throw new AssertionError(msg); + } +} +function yell(str) { + assert(typeof str === "string"); + + return str.toUppercase(); + // ~~~~~~~~~~~ + // error: La propiedad 'toUppercase' no existe en el tipo 'string'. + // Querías decir 'toUpperCase'? +} +``` + +También puede hacer assert sin una función personalizada +You can also assert without a custom function: + +```tsx +function assertIsString(val: any): asserts val is string { + if (typeof val !== "string") { + throw new AssertionError("Not a string!"); + } +} +function yell(str: any) { + assertIsString(str); + + // Ahora Typescript sabe que 'str' es de tipo 'string' + return str.toUppercase(); + // ~~~~~~~~~~~ + // error: La propiedad 'toUppercase' no existe el tipo 'string'. + // Querías decir 'toUpperCase'? +} +``` + +4. `ts-nocheck` + +Ahora puedes añadir `// @ts-nocheck` a la parte superior de los archivos Typescript! bueno para las migraciones. + +## TypeScript Roadmap y Especificaciones https://github.com/Microsoft/TypeScript/wiki/Roadmap +¿Sabía también que puede leer la especificación de TypeScript en línea? https://github.com/microsoft/TypeScript/blob/master/doc/spec.md + # Sección 3: Misceláneas A veces, escribir React no se trata solo de React. Si bien no nos centramos en otras bibliotecas como Redux (ver más abajo para obtener más información al respecto), aquí hay algunos consejos sobre otras preocupaciones comunes al hacer aplicaciones con React + TypeScript. @@ -1216,105 +1329,18 @@ yarn add -D prettier husky lint-staged } ``` -Esto está configurado para ti en [tsdx](https://github.com/palmerhq/tsdx/pull/45/files). - -## Linting - -> ⚠️ Nota que [TSLint ahora está en mantenimiento y deberías intentar usar ESLint en su lugar](https://medium.com/palantir/tslint-in-2019-1a144c2317a9). Si está interesado en los consejos de TSLint, consulte este PR desde [@azdanov](https://github.com/typescript-cheatsheets/react-typescript-cheatsheet/pull/14). El resto de esta sección solo se centra en ESLint. - -> ⚠️ Este es un tema en evolución. `typescript-eslint-parser` ya no se mantiene y [el trabajo ha comenzado recientemente sobre`typescript-eslint` en la comunidad ESLint](https://eslint.org/blog/2019/01/future-typescript-eslint) para lleve ESLint con TSLint. - -Siga los documentos de TypeScript + ESLint en https://github.com/typescript-eslint/typescript-eslint: - -``` -yarn add -D @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint -``` - -agregue un script `lint` a su`package.json`: - -```json - "scripts": { - "lint": "eslint 'src/**/*.ts'" - }, -``` - -y en `.eslintrc.json` adecuado: +Integrar esto con ESlint puede ser un problema. Todavía no hemos escrito mucho sobre esto, por favor contribuya si tiene una opinión firme. [Aquí hay un gist útil.](https://gist.github.com/JirkaVebr/519c7597517e4ba756d5b89e7cb4cc0e) -```json -{ - "env": { - "es6": true, - "node": true, - "jest": true - }, - "extends": "eslint:recommended", - "parser": "@typescript-eslint/parser", - "plugins": ["@typescript-eslint"], - "parserOptions": { - "ecmaVersion": 2017, - "sourceType": "module" - }, - "rules": { - "indent": ["error", 2], - "linebreak-style": ["error", "unix"], - "quotes": ["error", "single"], - "no-console": "warn", - "no-unused-vars": "off", - "@typescript-eslint/no-unused-vars": [ - "error", - { "vars": "all", "args": "after-used", "ignoreRestSiblings": false } - ], - "no-empty": "warn" - } -} -``` - -Esto está tomado de [el `tsdx` PR](https://github.com/palmerhq/tsdx/pull/70/files) que es para **bibliotecas**. +Esto está configurado para ti en [tsdx](https://github.com/palmerhq/tsdx/pull/45/files). -Más opciones de `.eslintrc.json` se pueden desear para **aplicaciones**: +## Testing -```json -{ - "extends": [ - "airbnb", - "prettier", - "prettier/react", - "plugin:prettier/recommended", - "plugin:jest/recommended", - "plugin:unicorn/recommended" - ], - "plugins": ["prettier", "jest", "unicorn"], - "parserOptions": { - "sourceType": "module", - "ecmaFeatures": { - "jsx": true - } - }, - "env": { - "es6": true, - "browser": true, - "jest": true - }, - "settings": { - "import/resolver": { - "node": { - "extensions": [".js", ".jsx", ".ts", ".tsx"] - } - } - }, - "overrides": [ - { - "files": ["**/*.ts", "**/*.tsx"], - "parser": "typescript-eslint-parser", - "rules": { - "no-undef": "off" - } - } - ] -} -``` +¡Sí, puedes probar tus tipos! No debe usarlo para TODO, pero puede ayudar a prevenir regresiones: -Puede leer una [guía de configuración más completa de TypeScript + ESLint aquí](https://blog.matterhorn.dev/posts/learn-typescript-linting-part-1/) de Matterhorn, en particular consulte https://github.com/MatterhornDev/learn-typescript-linting. +- https://github.com/azz/jest-runner-tsc +- https://github.com/SamVerschueren/tsd +- https://github.com/ikatyang/dts-jest ([Demo](https://codesandbox.io/s/dts-test-frozen-public-demo-iyorn)) +- https://github.com/microsoft/dtslint ([Intro to dtslint](https://www.youtube.com/watch?v=nygcFEwOG8w&feature=share) ## Trabajar con bibliotecas que no son de TypeScript (escribe tu propio index.d.ts) diff --git a/IGNORATE.md b/IGNORATE.md new file mode 100644 index 0000000..324231a --- /dev/null +++ b/IGNORATE.md @@ -0,0 +1,1462 @@ +
+ + + react + ts logo + + +

Cheatsheets for experienced React developers getting started with TypeScript

+ +[**Basic**](https://github.com/typescript-cheatsheets/react-typescript-cheatsheet#basic-cheatsheet-table-of-contents) | +[**Advanced**](https://github.com/typescript-cheatsheets/react-typescript-cheatsheet/blob/master/ADVANCED.md) | +[**Migrating**](https://github.com/typescript-cheatsheets/react-typescript-cheatsheet/blob/master/MIGRATING.md) | +[**HOC**](https://github.com/typescript-cheatsheets/react-typescript-cheatsheet/blob/master/HOC.md) | +[中文翻译](https://github.com/fi3ework/blog/tree/master/react-typescript-cheatsheet-cn) | +[**Español**](https://github.com/typescript-cheatsheets/react-typescript-cheatsheet-es) | +[Contribute!](https://github.com/typescript-cheatsheets/react-typescript-cheatsheet/blob/master/CONTRIBUTING.md) | +[Ask!](https://github.com/typescript-cheatsheets/react-typescript-cheatsheet/issues/new/choose) + +
+ +--- + +# Advanced Cheatsheet + +**This Advanced Cheatsheet** helps show and explain advanced usage of generic types for people writing reusable type utilities/functions/render prop/higher order components and TS+React **libraries**. + +- It also has miscellaneous tips and tricks for pro users. +- Advice for contributing to DefinitelyTyped +- The goal is to take _full advantage_ of TypeScript. + +**Creating React + TypeScript Libraries** + +The best tool for creating React + TS libraries right now is [`tsdx`](https://github.com/palmerhq/tsdx). Run `npx tsdx create` and select the "react" option. You can view [the React User Guide](https://github.com/palmerhq/tsdx/issues/5) for a few tips on React+TS library best practices and optimizations for production. + +- Be sure to also check [`basarat`'s guide](https://basarat.gitbooks.io/typescript/content/docs/quick/library.html) for library tsconfig settings. +- From the Angular world, check out https://github.com/bitjson/typescript-starter + +--- + +### Advanced Cheatsheet Table of Contents + +
+ +Expand Table of Contents + +- [Section 0: Utility Types](#section-0-utility-types) +- [Section 1: Reusable Components/Type Utilities](#section-1-reusable-componentstype-utilities) + - [Higher Order Components](#higher-order-components-hocs) + - [Render Props](#render-props) + - [Conditionally Rendering Components](#conditinonally-rendering-components) + - [`as` props (passing a component to be rendered)](#as-props-passing-a-component-to-be-rendered) + - [Generic Components](#generic-components) + - [Typing a Component that Accepts Different Props](#typing-a-component-that-accepts-different-props) + - [Props: One or the Other but not Both](#props-one-or-the-other-but-not-both) + - [Props: Must Pass Both](#props-must-pass-both) + - [Props: Can Optionally Pass One Only If the Other Is Passed](#props-can-optionally-pass-one-only-if-the-other-is-passed) + - [Omit attribute from a type](#omit-attribute-from-a-type) + - [Type Zoo](#type-zoo) + - [Extracting Prop Types of a Component](#extracting-prop-types-of-a-component) + - [Handling Exceptions](#handling-exceptions) + - [Third Party Libraries](#third-party-libraries) +- [Section 2: Useful Patterns by TypeScript Version](#section-2-useful-patterns-by-typescript-version) + - [TypeScript 2.9](#typescript-29) + - [TypeScript 3.0](#typescript-30) + - [TypeScript 3.1](#typescript-31) + - [TypeScript 3.2](#typescript-32) + - [TypeScript 3.3](#typescript-33) + - [TypeScript 3.4](#typescript-34) + - [TypeScript 3.5](#typescript-35) + - [TypeScript 3.6](#typescript-36) + - [TypeScript 3.7](#typescript-37) +- [Section 3: Misc. Concerns](#section-3-misc-concerns) + - [Writing TypeScript Libraries instead of Apps](#writing-typescript-libraries-instead-of-apps) + - [Commenting Components](#commenting-components) + - [Namespaced Components](#namespaced-components) + - [Design System Development](#design-system-development) + - [Migrating from Flow](#migrating-from-flow) + - [Prettier](#prettier) + - [Testing](#testing) + - [Linting](#linting) + - [Working with Non-TypeScript Libraries (writing your own index.d.ts)](#working-with-non-typescript-libraries-writing-your-own-indexdts) +- [Section 4: @types/react and @types/react-dom APIs](#section-4-typesreact-and-typesreact-dom-apis) + + - [Adding non-standard attributes](#adding-non-standard-attributes) +
+ +# Section 0: Utility Types + +We will assume knowledge of utility types covered in the sister project [`typescript-utilities-guide`](https://github.com/typescript-cheatsheets/typescript-utilities-guide). Look up libraries included there as well for your typing needs. + +# Section 1: Advanced Guides + +## Higher Order Components (HOCs) + +**There is now a dedicated [HOC cheatsheet](./HOC.md) you can refer to get some practice on HOCs.** + +## Render Props + +Sometimes you will want to write a function that can take a React element or a string or something else as a prop. The best Type to use for such a situation is `React.ReactNode` which fits anywhere a normal, well, React Node would fit: + +```tsx +export interface Props { + label?: React.ReactNode; + children: React.ReactNode; +} +export const Card = (props: Props) => { + return ( +
+ {props.label &&
{props.label}
} + {props.children} +
+ ); +}; +``` + +If you are using a function-as-a-child render prop: + +```tsx +export interface Props { + children: (foo: string) => React.ReactNode; +} +``` + +[Something to add? File an issue](https://github.com/typescript-cheatsheets/react-typescript-cheatsheet/issues/new/choose). + +## Conditionally Rendering Components + +Use [type guards](https://basarat.gitbooks.io/typescript/docs/types/typeGuard.html#user-defined-type-guards)! + +```tsx +// Button props +type ButtonProps = React.ButtonHTMLAttributes & { + href?: undefined; +}; + +// Anchor props +type AnchorProps = React.AnchorHTMLAttributes & { + href?: string; +}; + +// Input/output options +type Overload = { + (props: ButtonProps): JSX.Element; + (props: AnchorProps): JSX.Element; +}; + +// Guard to check if href exists in props +const hasHref = (props: ButtonProps | AnchorProps): props is AnchorProps => + "href" in props; + +// Component +const Button: Overload = (props: ButtonProps | AnchorProps) => { + // anchor render + if (hasHref(props)) return ; + // button render + return + {/* 😭 Error, `disabled` doesnt exist on anchor element */} + + + ); +} +``` + +[View in the TypeScript Playground](https://www.typescriptlang.org/play/?jsx=2#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wFgAoAekrgCEBXGGCAOzjBzAGcKYBPMEjqNmLAAqcucALyJiMAHQMmrABIAVALIAZAIJMowAEaMkXADwady0QFEANkhBIWMAHxwAZHADeFOHAAFkSYAPwAXHD0LAAmSJjALEgxANwUAL5p5BTUcLosaIHQ7JK8AkL5hdASENwycuiKlUVQVnoGxqYWbc3QDk4u7l6+-kEhEXBcMIYsAOZZmRQ5NACSLGCMlBCMG-C1MMCsPOT8gnAA8gBuSFD2ECgx9X7kAQAUHLVckTasNdwAlJEAFIAZQAGgp+s5XFk3h9uJFelA-lxAXBQRCoYMFlllnAAOL0FBQR7MOCFJBoADWcGAmDG8TgSAAHsAplJEiVPhQ0Ed4IEUFxVCF6u9JN8RL9JHAAD55AotFFo+EcqRIlEyNyjABEwXi2tpbBVuKoNAAwrhIElXDy+cIVCxIlcbncHqKVRKHRq5erJP9NSMXnBcigFcUiLEbqM6XBXgKhSExZ9-v6iDB6FA2OYUL4FHmVelg25YcGaCYHXAI3EoKM0xms+XRLn85JC5RixkTbkAKpcFCzJAUTDRDCHNi6MBgV7+54BOuZ2OjALmLVBgIBHyUABUcEAvBuAOD28vZ7HBZhAII8t5R0kv1+YfmwYMSBzBpNqAPpGeyhqkGvWYN9AiYBFqAAd3AhQzwgWZHAUXkQG1Vd12QuB1DMGBb2XSgHyQlDNx3XdAFo9uBbCgHAoAAGjgAADGI2RQL9kmouAYggMxXCZVkpjgVg4FDKooCZRxoXgK8bzXO8HxY+jGMef832ZRDMPXNCpmU8xsMlFhcKw3D-gWIA) + +## `as` props (passing a component to be rendered) + +`ElementType` is pretty useful to cover most types that can be passed to createElement e.g. + +```tsx +function PassThrough(props: { as: React.ElementType }) { + const { as: Component } = props; + + return ; +} +``` + +[Thanks @eps1lon](https://github.com/typescript-cheatsheets/react-typescript-cheatsheet/pull/69) for this + +## Generic Components + +Just as you can make generic functions and classes in TypeScript, you can also make generic components to take advantage of the type system for reusable type safety. Both Props and State can take advantage of the same generic types, although it probably makes more sense for Props than for State. You can then use the generic type to annotate types of any variables defined inside your function / class scope. + +```tsx +interface Props { + items: T[]; + renderItem: (item: T) => React.ReactNode; +} +function List(props: Props) { + const { items, renderItem } = props; + const [state, setState] = React.useState([]); // You can use type T in List function scope. + return ( +
+ {items.map(renderItem)} + + {JSON.stringify(state, null, 2)} +
+ ); +} +``` + +You can then use the generic components and get nice type safety through type inference: + +```tsx +ReactDOM.render( + ( +
  • + {item.toPrecision(3)} // Error: Property 'toPrecision' does not exist on + type 'string'. +
  • + )} + />, + document.body +); +``` + +As of [TS 2.9](#typescript-29), you can also supply the type parameter in your JSX to opt out of type inference: + +```tsx +ReactDOM.render( + + items={["a", "b"]} // Error: Type 'string' is not assignable to type 'number'. + renderItem={item =>
  • {item.toPrecision(3)}
  • } + />, + document.body +); +``` + +You can also use Generics using fat arrow function style: + +```tsx +interface Props { + items: T[]; + renderItem: (item: T) => React.ReactNode; +} + +// Note the before the function definition. +// You can't use just `` as it will confuse the TSX parser whether it's a JSX tag or a Generic Declaration. +// You can also use https://github.com/microsoft/TypeScript/issues/15713#issuecomment-499474386 +const List = (props: Props) => { + const { items, renderItem } = props; + const [state, setState] = React.useState([]); // You can use type T in List function scope. + return ( +
    + {items.map(renderItem)} + + {JSON.stringify(state, null, 2)} +
    + ); +}; +``` + +The same for using classes: (Credit: [Karol Majewski](https://twitter.com/WrocTypeScript/status/1163234064343736326)'s [gist](https://gist.github.com/karol-majewski/befaf05af73c7cb3248b4e084ae5df71)) + +```tsx +interface Props { + items: T[]; + renderItem: (item: T) => React.ReactNode; +} + +interface State { + items: T[]; +} + +class List extends React.PureComponent, State> { + // You can use type T inside List class. + state: Readonly> = { + items: [] + }; + render() { + const { items, renderItem } = this.props; + // You can use type T inside List class. + const clone: T[] = items.slice(0); + return ( +
    + {items.map(renderItem)} + + {JSON.stringify(this.state, null, 2)} +
    + ); + } +} +``` + +Though you can't use Generic Type Parameters for Static Members: + +```tsx +class List extends React.PureComponent, State> { + // Static members cannot reference class type parameters.ts(2302) + static getDerivedStateFromProps(props: Props, state: State) { + return { items: props.items }; + } +} +``` + +To fix this you need to convert your static function to a type inferred function: + +```tsx +class List extends React.PureComponent, State> { + static getDerivedStateFromProps(props: Props, state: State) { + return { items: props.items }; + } +} +``` + +### Generic components with children + +`children` is usually not defined as a part of the props type. Unless `children` are explicitly defined as a part of the `props` type, an attempt to use `props.children` in JSX or in the function body will fail: + +```tsx +interface WrapperProps { + item: T; + renderItem: (item: T) => React.ReactNode; +} + +/* Property 'children' does not exist on type 'WrapperProps'. */ +const Wrapper = (props: WrapperProps) => { + return ( +
    + {props.renderItem(props.item)} + {props.children} +
    + ); +}; + +/* +Type '{ children: string; item: string; renderItem: (item: string) => string; }' is not assignable to type 'IntrinsicAttributes & WrapperProps'. + Property 'children' does not exist on type 'IntrinsicAttributes & WrapperProps'. +*/ + +const wrapper = ( + item}> + {test} + +); +``` + +[View in the TypeScript Playground](https://www.typescriptlang.org/play/?jsx=2#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wFgAoC4AOxiSk3STgHUoUwx6AFHMAZwA8AFQB8cAN4U4cYHRAAuOMIDc0uEWoATegEl5SgBRyki5QEo4AXnHJ0MAHR2MAOQg615GWgAWwADZamkrOjqFuHhQAvhQUAPQAVHC8EFywAJ4EvgFBSNT4cFoQSPxw1BDwSAAewPzwENRwMOlcBGwcaSkCIqL4DnAJcRRoDXWs7Jz01nAicNV02qUSUaKGYHz8Su2TUF1CYpY2kupEMACuUI2G6jKCWsAAbqI3MpLrqfwOmjpQ+qZrGwcJhA5hiXleMgk7wEDmygU0YIhgji9ye6nMniinniCQowhazHwEjgcNy1CUdSgNAA5ipZAY4JSaXTvnoGcYGUzqNTDuIubS4FECrUyhU4Ch+PxgNTqCgAEb+ZgwCBNAkEXS0KnUKVoACCMBgVLlZzopQAZOMOjwNoJ+b0HOouvRmlk-PC8gUiiVRZUamMGqrWvgNYaaDr9aHjaa4Bbtp0bXa+hRBrFyCNtfBTfArHBDLyZqjRAAJJD+fwqrPIwvDUbwADuEzS02u4MEcamwKsACIs12NHkfn8QFYJMDrOJgSsXhIs4iZnF21BnuQMUA) + +To work around that, either add `children` to the `WrapperProps` definition (possibly narrowing down its type, as needed): + +```tsx +interface WrapperProps { + item: T; + renderItem: (item: T) => React.ReactNode; + children: string; // The component will only accept a single string child +} + +const Wrapper = (props: WrapperProps) => { + return ( +
    + {props.renderItem(props.item)} + {props.children} +
    + ); +}; +``` + +or wrap the type of the props in `React.PropsWithChildren` (this is what `React.FC<>` does): + +```tsx +interface WrapperProps { + item: T; + renderItem: (item: T) => React.ReactNode; +} + +const Wrapper = ( + props: React.PropsWithChildren> +) => { + return ( +
    + {props.renderItem(props.item)} + {props.children} +
    + ); +}; +``` + +## Typing a Component that Accepts Different Props + +Components, and JSX in general, are analogous to functions. When a component can render differently based on their props, it's similar to how a function can be overloaded to have multiple call signatures. In the same way, you can overload a function component's call signature to list all of its different "versions". + +A very common use case for this is to render something as either a button or an anchor, based on if it receives a `href` attribute. + +```tsx +type ButtonProps = JSX.IntrinsicElements["button"]; +type AnchorProps = JSX.IntrinsicElements["a"]; + +// optionally use a custom type guard +function isPropsForAnchorElement( + props: ButtonProps | AnchorProps +): props is AnchorProps { + return "href" in props; +} + +function Clickable(props: ButtonProps | AnchorProps) { + if (isPropsForAnchorElement(props)) { + return
    ; + } else { + return