From b8bd0375051b0ee792c4eeecb9e1096191265b03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Tammerg=C3=A5rd?= Date: Fri, 15 May 2026 17:03:44 +0200 Subject: [PATCH] restructure menu --- CONTRIBUTING.md | 2 +- README.md | 156 +-------- docs/advanced/index.md | 20 -- docs/advanced/misc-concerns.md | 175 ----------- docs/advanced/types-react-ap.md | 154 --------- docs/advanced/utility-types.md | 13 - .../getting-started/basic-type-examples.md | 6 +- .../basic/getting-started/class-components.md | 2 - docs/basic/getting-started/concurrent.md | 2 - docs/basic/getting-started/default-props.md | 2 - .../basic/getting-started/error-boundaries.md | 2 - .../getting-started/forward-create-ref.md | 2 +- docs/basic/getting-started/hooks.md | 2 - .../getting-started}/patterns_by_usecase.md | 2 - docs/basic/linting.md | 101 ------ docs/hoc/excluding-props.md | 131 -------- docs/hoc/full-example.md | 99 ------ docs/hoc/index.md | 65 ---- docs/hoc/react-hoc-docs.md | 297 ------------------ docs/react-types/index.md | 10 - .../CSSProperties.md | 0 .../ComponentProps.md | 0 docs/{react-types => reference}/ReactNode.md | 2 - docs/{react-types => reference}/Ref.md | 0 genReadme.mjs | 9 - package.json | 3 +- website/docusaurus.config.js | 12 +- website/package.json | 1 + website/sidebars.json | 67 ++-- website/src/pages/index.js | 4 +- 30 files changed, 56 insertions(+), 1285 deletions(-) delete mode 100644 docs/advanced/index.md delete mode 100644 docs/advanced/misc-concerns.md delete mode 100644 docs/advanced/types-react-ap.md delete mode 100644 docs/advanced/utility-types.md rename docs/{advanced => basic/getting-started}/patterns_by_usecase.md (99%) delete mode 100644 docs/basic/linting.md delete mode 100644 docs/hoc/excluding-props.md delete mode 100644 docs/hoc/full-example.md delete mode 100644 docs/hoc/index.md delete mode 100644 docs/hoc/react-hoc-docs.md delete mode 100644 docs/react-types/index.md rename docs/{react-types => reference}/CSSProperties.md (100%) rename docs/{react-types => reference}/ComponentProps.md (100%) rename docs/{react-types => reference}/ReactNode.md (97%) rename docs/{react-types => reference}/Ref.md (100%) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 757576413..a5ded6d2f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,7 +4,7 @@ We appreciate your interest in contributing to this project. Here are some core ## 📋 Core Principles -1. **We're All About Cheatsheets**: Our main goal is to provide concise and easy-to-use cheatsheets. All code examples should be simple, easily searchable, and ready for copy-and-paste. +1. **Cheatsheet Style**: Our main goal is to provide a concise and easy-to-use cheatsheet. All code examples should be simple, easily searchable, and ready for copy-and-paste. 2. **Collapsible Explanations**: Keep explanations short and sweet, limited to 1-2 sentences. For more in-depth explanations, use `details` tags to provide additional context. diff --git a/README.md b/README.md index 3ca1dba77..7064917db 100644 --- a/README.md +++ b/README.md @@ -24,38 +24,30 @@ Cheatsheet for using React with TypeScript. [![All Contributors](https://img.shields.io/github/contributors/typescript-cheatsheets/react-typescript-cheatsheet?color=orange&style=flat-square)](/CONTRIBUTORS.md) | [![Discord](https://img.shields.io/discord/508357248330760243.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/wTGS5z9) -- [The Basic Cheatsheet](https://react-typescript-cheatsheet.netlify.app/docs/basic/setup) is focused on helping React devs just start using TS in React **apps** - - Focus on opinionated best practices, copy+pastable examples. - - Explains some basic TS types usage and setup along the way. - - Answers the most Frequently Asked Questions. - - Does not cover generic type logic in detail. Instead we prefer to teach simple troubleshooting techniques for newbies. - - The goal is to get effective with TS without learning _too much_ TS. -- [The Advanced Cheatsheet](https://react-typescript-cheatsheet.netlify.app/docs/advanced) 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. -- [The HOC Cheatsheet](https://react-typescript-cheatsheet.netlify.app/docs/hoc) specifically teaches people to write HOCs with examples. - - Familiarity with [Generics](https://www.typescriptlang.org/docs/handbook/2/generics.html) is necessary. - - ⚠️This is the newest cheatsheet, all assistance is welcome. +[The Cheatsheet](https://react-typescript-cheatsheet.netlify.app/docs/basic/setup) is focused on helping React devs use TypeScript effectively: + +- Opinionated best practices and copy+pastable examples. +- Covers basic TS types and setup, plus advanced usage of generic types for people writing reusable type utilities and React+TS **libraries**. +- Advice for contributing to DefinitelyTyped. --- -## Basic Cheatsheet +## Cheatsheet -### Basic Cheatsheet Table of Contents +### Table of Contents
Expand Table of Contents - [React TypeScript Cheatsheet](#react-typescript-cheatsheet) - - [Basic Cheatsheet](#basic-cheatsheet) - - [Basic Cheatsheet Table of Contents](#basic-cheatsheet-table-of-contents) - - [Section 1: Setup](#section-1-setup) + - [Cheatsheet](#cheatsheet) + - [Table of Contents](#table-of-contents) + - [Setup](#setup) - [Prerequisites](#prerequisites) - [React and TypeScript starter kits](#react-and-typescript-starter-kits) - [Try React and TypeScript online](#try-react-and-typescript-online) - - [Section 2: Getting Started](#section-2-getting-started) + - [Getting Started](#getting-started) - [Function Components](#function-components) - [Hooks](#hooks) - [useState](#usestate) @@ -106,7 +98,6 @@ Cheatsheet for using React with TypeScript. - [Option 1: Using react-error-boundary](#option-1-using-react-error-boundary) - [Option 2: Writing your custom error boundary component](#option-2-writing-your-custom-error-boundary-component) - [Concurrent React/React Suspense](#concurrent-reactreact-suspense) - - [Linting](#linting) - [My question isn't answered here!](#my-question-isnt-answered-here) - [Contributors](#contributors) @@ -114,7 +105,7 @@ Cheatsheet for using React with TypeScript. -### Section 1: Setup +### Setup #### Prerequisites @@ -148,7 +139,7 @@ There are some tools that let you run React and TypeScript online, which can be -### Section 2: Getting Started +### Getting Started @@ -618,8 +609,6 @@ If you are writing a React Hooks library, don't forget that you should also expo - https://github.com/palmerhq/the-platform - https://github.com/sw-yx/hooks -[Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new). - @@ -729,8 +718,6 @@ class App extends React.Component<{ [View in the TypeScript Playground](https://www.typescriptlang.org/play/?jsx=2#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wFgAoCtAGxQGc64BBMMOJADxiQDsATRsnQwAdAGFckHrxgAeAN4U4cEEgYoA5kgBccOjCjAeGgNwUAvgD44i8sshHuUXTwCuIAEZIoJuAHo-OGpgAGskOBgAC2A6JTg0SQhpHhgAEWA+AFkIVxSACgBKGzjlKJiRBxTvOABeOABmMzs4cziifm9C4ublIhhXKB44PJLlOFk+YAA3S1GxmzK6CpwwJdV1LXM4FH4F6KXKp1aesdk-SZnRgqblY-MgA) -[Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new). - #### Typing getDerivedStateFromProps Before you start using `getDerivedStateFromProps`, please go through the [documentation](https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops) and [You Probably Don't Need Derived State](https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html). Derived State can be implemented using hooks which can also help set up memoization. @@ -874,8 +861,6 @@ For most apps this isn't needed — only library authors who re-export the props
-[Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new). - @@ -970,7 +955,7 @@ export declare interface AppProps { childrenElement: React.JSX.Element; // A single React element style?: React.CSSProperties; // to pass through style props onChange?: React.FormEventHandler; // form events! the generic parameter is the type of event.target - // more info: https://react-typescript-cheatsheet.netlify.app/docs/advanced/patterns_by_usecase/#wrappingmirroring + // more info: https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/patterns_by_usecase/#wrappingmirroring props: Props & React.ComponentPropsWithoutRef<"button">; // to impersonate all the props of a button element and explicitly not forwarding its ref props2: Props & React.ComponentPropsWithRef; // to impersonate all the props of MyButtonForwardedRef and explicitly forwarding its ref } @@ -988,8 +973,6 @@ Quote [@ferdaber](https://github.com/typescript-cheatsheets/react/issues/57): A [More discussion: Where ReactNode does not overlap with React.JSX.Element](https://github.com/typescript-cheatsheets/react/issues/129) -[Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new). - #### Types or Interfaces? You can use either Types or Interfaces to type Props and State, so naturally the question arises - which do you use? @@ -1038,8 +1021,6 @@ It's a nuanced topic, don't get too hung up on it. Here's a handy table: (source: [Karol Majewski](https://twitter.com/karoljmajewski/status/1082413696075382785)) -[Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new). - @@ -1443,7 +1424,7 @@ function Parent() { } ``` -**Read more**: [Wrapping/Mirroring a HTML Element](/docs/advanced/patterns_by_usecase#wrappingmirroring-a-html-element) +**Read more**: [Wrapping/Mirroring a HTML Element](/docs/basic/getting-started/patterns_by_usecase#wrappingmirroring-a-html-element) #### Legacy Approaches (Pre-React 19) @@ -1782,8 +1763,6 @@ export default ErrorBoundary; ``` -[Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new). - @@ -1937,113 +1916,8 @@ The standalone version does not provide an `isPending` flag — use the hook if - [`useActionState`, `useFormStatus`, `useOptimistic`](https://react.dev/reference/react) — built on top of transitions - [Server Components and `'use server'`](https://react.dev/reference/rsc/server-components) -[Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new). - - - -### Linting - -Follow the TypeScript + ESLint docs at https://github.com/typescript-eslint/typescript-eslint: - -``` -yarn add -D @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint -``` - -add a `lint` script to your `package.json`: - -```json - "scripts": { - "lint": "eslint 'src/**/*.ts'" - }, -``` - -and a suitable `.eslintrc.js` (using `.js` over `.json` here so we can add comments): - -```js -module.exports = { - 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 }, - ], - "@typescript-eslint/explicit-function-return-type": "warn", // Consider using explicit annotations for object literals and function return types even when they can be inferred. - "no-empty": "warn", - }, -}; -``` - -Most of this is taken from [the `tsdx` PR](https://github.com/palmerhq/tsdx/pull/70/files) which is for **libraries**. - -More `.eslintrc.json` options to consider with more options you may want for **apps**: - -```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" - } - } - ] -} -``` - -Another great resource is ["Using ESLint and Prettier in a TypeScript Project"](https://dev.to/robertcoopercode/using-eslint-and-prettier-in-a-typescript-project-53jb) by @robertcoopercode. - -Wes Bos is also working on [TypeScript support for his eslint+prettier config.](https://github.com/wesbos/eslint-config-wesbos/issues/68) - -If you're looking for information on Prettier, check out the [Prettier](https://github.com/typescript-cheatsheets/react/blob/main/docs/advanced/misc-concerns.md#prettier) guide. - - - ## My question isn't answered here! - [File an issue](https://github.com/typescript-cheatsheets/react-typescript-cheatsheet/issues/new). diff --git a/docs/advanced/index.md b/docs/advanced/index.md deleted file mode 100644 index af3a48dd3..000000000 --- a/docs/advanced/index.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -id: intro -sidebar_label: Intro -title: 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. - -Another option is [Rollpkg](https://github.com/rafgraph/rollpkg), which uses Rollup and the TypeScript compiler (not Babel) to create packages. It includes default configs for TypeScript, Prettier, ESLint, and Jest (setup for use with React), as well as Bundlephobia package stats for each build. - -- Alec Larson: [The best Rollup config for TypeScript libraries](https://gist.github.com/aleclarson/9900ed2a9a3119d865286b218e14d226) -- From the Angular world, check out https://github.com/bitjson/typescript-starter diff --git a/docs/advanced/misc-concerns.md b/docs/advanced/misc-concerns.md deleted file mode 100644 index 9633136ea..000000000 --- a/docs/advanced/misc-concerns.md +++ /dev/null @@ -1,175 +0,0 @@ ---- -id: misc_concerns -title: "Section 3: Misc. Concerns" -sidebar_label: Misc. Concerns ---- - -Sometimes writing React isn't just about React. While we don't focus on other libraries like Redux (see below for more on that), here are some tips on other common concerns when making apps with React + TypeScript. - -## Writing TypeScript Libraries instead of Apps - -`propTypes` may seem unnecessary with TypeScript, especially when building React + TypeScript **apps**, but they are still relevant when writing **libraries** which may be used by developers working in Javascript. - -```ts -interface MyComponentProps { - autoHeight: boolean; - secondProp: number; -} - -export class MyComponent extends React.Component { - static propTypes = { - autoHeight: PropTypes.bool, - secondProp: PropTypes.number.isRequired, - }; -} -``` - -[Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new). - -## Commenting Components - -TypeScript uses [TSDoc](https://github.com/Microsoft/tsdoc), a variant of JSDoc for TypeScript. This is very handy for writing component libraries and having useful descriptions pop up in autocomplete and other tooling. The main thing to remember is to use `/** YOUR_COMMENT_HERE */` syntax in the line just above whatever you're annotating. - -```tsx -interface MyComponentProps { - /** Description of prop "label". - * @default foobar - * */ - label?: string; -} - -/** - * General component description in JSDoc format. Markdown is *supported*. - */ -export default function MyComponent({ label = "foobar" }: MyComponentProps) { - return
Hello world {label}
; -} -``` - -[View in the TypeScript Playground](https://www.typescriptlang.org/play/?jsx=2#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wFgAoC4AOxiSk3STgFkBPABRzAGc4BvCnDgB6AFRi4AESQ80UYGBjAI1OBExww3OACIANigBGSfboB0Q4ZIACAEySMArvqwQIRlFCtxJYkVaGJvoA-ABccDwwCtQA5gDcFAC+FBTiYkKSAOJI1PQo+nBouJB5tHAOcgpKKmo0cABSAMpSEGhwmNAgKDDmrF4A1nYQAO51fGI8TmCQsEh2YpbkvgHkSAAes-AOzq4dTtQYtaxsAMIlqrkwABT8cEGmcAC8ep0eXrpwSRHsXBC8AEoBFYiDAnFA1AAeOzAABuAD4ABKmfQQOAjaD6OwCB76JKQkQwhGJchJIA) - -[Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new). - -## Namespaced Components - -Often when creating similar components or components that have a parent-child relationship, it is useful to namespace your components. Types can easily be added be using `Object.assign()`; - -```tsx -import { forwardRef } from "react"; - -const Input = (props: any) => ; - -const Form = forwardRef( - ({ children, ...otherProps }, ref) => ( -
- {children} -
- ) -); - -/** - * Exported components now can be used as `
` and `` - */ -export default Object.assign(Form, { Input: Input }); -``` - -[View in the TypeScript Playground](https://www.typescriptlang.org/play/?jsx=2&ssl=1&ssc=1&pln=14&pc=52#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wFgAoCtCAOwGd4BJGsAV3gF44AKMHMOgC44KGgE8AlHA4A+OAB5gLdnADeAOk18IAgL5wA9DIpVaDOADFoeLsnQx1maAHcUUACbJM8gBIAVAFkAGQARYAA3AFEAGyQQJBoYABoRcRlublU0AAtgaPciGhTNdQgYbKQoAAV+Ol0UokwpWR4KOAUnKDwNTTKK6tr9Ro5VRt1jcnb2rNz8wt02hQNOkAmJCQBuE3IDACpdtt24SIAPSFgkdzhqcFoEmDo4Gghna9E4ACMkOFY6S5FHgADeRWLoyQGpK7A0EgdTMNgwcGHAwUJBnaDwdxITAoVjReAAeQ+ACskBh1Cg6HRgABzGjcGEpVTw9jCFkwXSbIA) - -(Contributed by @bryceosterhaus, see [further discussion](https://github.com/typescript-cheatsheets/react/issues/165)) - -[Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new). - -## Design System Development - -I do like [Docz](https://docz.site/) which takes basically [1 line of config](https://www.docz.site/documentation/project-configuration#typescript) to accept TypeScript. However it is newer and has a few more rough edges (many breaking changes since it is still < v1.0) - -For developing with Storybook, read the docs I wrote over here: [https://storybook.js.org/configurations/typescript-config/](https://storybook.js.org/configurations/typescript-config/). This includes automatic proptype documentation generation, which is awesome :) - -[Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new). - -## Prettier - -There isn't any real secret to Prettier for TypeScript. But its a great idea to run prettier on every commit! - -```bash -$ yarn add -D prettier husky lint-staged -``` - -```json -// inside package.json -{ - //... - "husky": { - "hooks": { - "pre-commit": "lint-staged" - } - }, - "lint-staged": { - "linters": { - "src/*.{ts,tsx,js,jsx,css,scss,md}": [ - "prettier --trailing-comma es5 --single-quote --write", - "git add" - ], - "ignore": ["**/dist/*, **/node_modules/*"] - } - }, - "prettier": { - "printWidth": 80, - "semi": false, - "singleQuote": true, - "trailingComma": "es5" - } -} -``` - -Integrating this with ESlint may be a problem. We haven't written much on this yet, please contribute if you have a strong opinion. [Here's a helpful gist.](https://gist.github.com/JirkaVebr/519c7597517e4ba756d5b89e7cb4cc0e) - -For library authors, this is set up for you in [tsdx](https://github.com/palmerhq/tsdx/pull/45/files). - -## Testing - -Yes, you can test your types! You shouldn't use it for EVERYTHING, but it can help prevent regressions: - -- 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)) - -## Working with Non-TypeScript Libraries (writing your own index.d.ts) - -Lets say you want to use `de-indent`, but it isn't typed or on DefinitelyTyped. You get an error like this: - -``` -[ts] -Could not find a declaration file for module 'de-indent'. '/Users/swyx/Work/react-sfc-loader/node_modules/de-indent/index.js' implicitly has an 'any' type. - Try `npm install @types/de-indent` if it exists or add a new declaration (.d.ts) file containing `declare module 'de-indent';` [7016] -``` - -So create a `.d.ts` file anywhere in your project with the module definition: - -```ts -// de-indent.d.ts -declare module "de-indent" { - function deindent(): void; - export = deindent; // default export -} -``` - -
- -Further Discussion - -Any other tips? Please contribute on this topic! [We have an ongoing issue here with some references](https://github.com/typescript-cheatsheets/react/issues/8). We have more discussion and examples [in our issue here](https://github.com/typescript-cheatsheets/react/issues/12). - -
- -## Compilation Speed - -Compiling large TS projects can get slow. Here are some tips: - -- We have a dedicated repo tracking TS speed recommendations: https://github.com/typescript-cheatsheets/speed -- Use [TypeScript Project references](https://www.typescriptlang.org/docs/handbook/project-references.html) -- Check the official [TS performance wiki guidelines](https://github.com/microsoft/TypeScript/wiki/Performance) - note that [Dan Rossenwasser says to take it with a grain of salt](https://news.ycombinator.com/item?id=25199070) -- Webpack ([see CRA diff](https://gist.github.com/jaredpalmer/d3016701589f14df8a3572df91a5754b)): - - set `output.pathinfo = false` - - set `optimization.splitChunks`, `optimization.removeAvailableModules`, `optimization.removeEmptyChunks` to `false` diff --git a/docs/advanced/types-react-ap.md b/docs/advanced/types-react-ap.md deleted file mode 100644 index 6961c7d61..000000000 --- a/docs/advanced/types-react-ap.md +++ /dev/null @@ -1,154 +0,0 @@ ---- -id: types_react_api -title: "Section 4: @types/react and @types/react-dom APIs" -sidebar_label: "@types/react and @types/react-dom APIs" ---- - -The `@types` typings export both "public" types meant for your use as well as "private" types that are for internal use. - -Check [SaltyCrane's React TypeScript Cheatsheet](https://github.com/saltycrane/typescript-cheatsheet) for a nice autogenerated complete reference. - -## `@types/react` - -[Link to `.d.ts`](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts) - -**Namespace: React** - -Most Commonly Used Interfaces and Types - -- `ReactNode` - anything that is renderable _inside_ of JSX, this is NOT the same as what can be rendered by a component! -- `Component` - base class of all class-based components -- `PureComponent` - base class for all class-based optimized components -- `FC`, `FunctionComponent` - a complete interface for function components, often used to type external components instead of typing your own -- `CSSProperties` - used to type style objects -- all events: used to type event handlers -- all event handlers: used to type event handlers -- all consts: `Children`, `Fragment`, ... are all public and reflect the React runtime namespace - -Not Commonly Used but Good to know - -- `Ref` - used to type `innerRef` -- `ElementType` - used for higher order components or operations on components, e.g. [Polymorphic Components](https://react-typescript-cheatsheet.netlify.app/docs/advanced/patterns_by_usecase#polymorphic-components) -- `ReactElement` - [can be used if you want to pass it to `cloneElement`](https://www.reddit.com/r/reactjs/comments/ia8sdi/any_other_typescript_users_constantly_confused/g1npahe/) aka it's pretty rarely used -- `ComponentType` - used for higher order components where you don't specifically deal with the intrinsic components -- `ReactPortal` - used if you specifically need to type a prop as a portal, otherwise it is part of `ReactNode` -- `ComponentClass` - a complete interface for the produced constructor function of a class declaration that extends `Component`, often used to type external components instead of typing your own -- `JSXElementConstructor` - anything that TypeScript considers to be a valid thing that can go into the opening tag of a JSX expression -- `ComponentProps` - props of a component - most useful for [Wrapping/Mirroring a HTML Element](https://react-typescript-cheatsheet.netlify.app/docs/advanced/patterns_by_usecase#wrappingmirroring-a-html-element) -- `ComponentPropsWithRef` - props of a component where if it is a class-based component it will replace the `ref` prop with its own instance type -- `ComponentPropsWithoutRef` - props of a component without its `ref` prop -- `HTMLProps` and `HTMLAttributes` - these are the most generic versions, for global attributes (see a list of [attributes marked as "global attribute" on MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes)). In general, prefer `React.ComponentProps`, `React.JSX.IntrinsicElements`, or [specialized HTMLAttributes interfaces](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/a2aa0406e7bf269eef01292fcb2b24dee89a7d2b/types/react/index.d.ts#L1914-L2625): - -
- - List of specialized HTMLAttributes - - -Note that there are about 50 of these, which means there are some HTML elements which are not covered. - -- `AnchorHTMLAttributes` -- `AudioHTMLAttributes` -- `AreaHTMLAttributes` -- `BaseHTMLAttributes` -- `BlockquoteHTMLAttributes` -- `ButtonHTMLAttributes` -- `CanvasHTMLAttributes` -- `ColHTMLAttributes` -- `ColgroupHTMLAttributes` -- `DataHTMLAttributes` -- `DetailsHTMLAttributes` -- `DelHTMLAttributes` -- `DialogHTMLAttributes` -- `EmbedHTMLAttributes` -- `FieldsetHTMLAttributes` -- `FormHTMLAttributes` -- `HtmlHTMLAttributes` -- `IframeHTMLAttributes` -- `ImgHTMLAttributes` -- `InsHTMLAttributes` -- `InputHTMLAttributes` -- `KeygenHTMLAttributes` -- `LabelHTMLAttributes` -- `LiHTMLAttributes` -- `LinkHTMLAttributes` -- `MapHTMLAttributes` -- `MenuHTMLAttributes` -- `MediaHTMLAttributes` -- `MetaHTMLAttributes` -- `MeterHTMLAttributes` -- `QuoteHTMLAttributes` -- `ObjectHTMLAttributes` -- `OlHTMLAttributes` -- `OptgroupHTMLAttributes` -- `OptionHTMLAttributes` -- `OutputHTMLAttributes` -- `ParamHTMLAttributes` -- `ProgressHTMLAttributes` -- `SlotHTMLAttributes` -- `ScriptHTMLAttributes` -- `SelectHTMLAttributes` -- `SourceHTMLAttributes` -- `StyleHTMLAttributes` -- `TableHTMLAttributes` -- `TextareaHTMLAttributes` -- `TdHTMLAttributes` -- `ThHTMLAttributes` -- `TimeHTMLAttributes` -- `TrackHTMLAttributes` -- `VideoHTMLAttributes` -- `WebViewHTMLAttributes` - -
- -- all methods: `createElement`, `cloneElement`, ... are all public and reflect the React runtime API - -[@Ferdaber's note](https://github.com/typescript-cheatsheets/react/pull/69): I discourage the use of most `...Element` types because of how black-boxy `React.JSX.Element` is. You should almost always assume that anything produced by `React.createElement` is the base type `React.ReactElement`. - -**Namespace: JSX** - -- `Element` - the type of any JSX expression. You should ideally never need to see or use this, but you do because of [a limitation of TypeScript](https://github.com/microsoft/TypeScript/issues/21699). -- `LibraryManagedAttributes` - It specifies other places where JSX elements can declare and initialize property types. Used to resolve static `defaultProps` and `propTypes` with the internal props type of a component. -- `IntrinsicElements` - every possible built-in component that can be typed in as a lowercase tag name in JSX. If you're using this to get the attributes for a HTML element, `React.ComponentProps` may be more readable as it doesn't require knowing what "Intrinsic" means. - -Not commonly used but good to know - -- `IntrinsicAttributes` set of attributes that all `IntrinsicElements` support... basically just `key`. -- `ElementChildrenAttribute` name of property that TS looks at to figure out what types of children a component supports. Basically the `children` property -- `ElementAttributesProperty` name of property that TS looks at to figure out what attributes a component supports. Basically the `props` property (for a class instance) - -**Don't use/Internal/Deprecated** - -Anything not listed above is considered an internal type and not public. If you're not sure you can check out the source of `@types/react`. The types are annotated accordingly. - -- `SFCElement` -- `SFC` -- `ComponentState` -- `LegacyRef` -- `StatelessComponent` -- `ReactType` - -### Adding non-standard attributes - -The attributes allowed on host components such as `button` or `img` follow the -[HTML living standard](https://html.spec.whatwg.org/). New features that are not yet part of the living standard -or are only implemented by certain browsers will therefore cause a type error. If -you specifically write code for these browsers or polyfill these attributes you can -use [module augmentation](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation) to still get those components type checked without having -to use `any` or `@ts-ignore`. - -In this example we'll add the [`loading`](https://www.chromestatus.com/feature/5645767347798016) attribute which adds support for [lazy-loading](https://web.dev/native-lazy-loading) images on Chrome: - -```ts -// react-unstable-attributes.d.ts -import "react"; - -declare module "react" { - interface ImgHTMLAttributes extends HTMLAttributes { - loading?: "auto" | "eager" | "lazy"; - } -} -``` - -## `@types/react-dom` - -To be written diff --git a/docs/advanced/utility-types.md b/docs/advanced/utility-types.md deleted file mode 100644 index 55150dc86..000000000 --- a/docs/advanced/utility-types.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -id: utility_types -title: "Utility Types" -sidebar_label: Utility Types ---- - -We will assume knowledge of utility types covered in the sister project [`typescript-cheatsheets/utilities`](https://github.com/typescript-cheatsheets/utilities). Look up libraries included there as well for your typing needs. - -If you intend to maintain a large TS codebase/a nontrivial React+TS library, **we strongly recommend exploring these utilities** so that you don't reinvent the wheel and/or lose sanity trying to do so. Studying their code can also teach you a lot of advanced TS that is not covered here. - -A level of comfort with **generic types** is therefore required. Here are some helpful resources: - -- https://ts.chibicode.com/generics/ diff --git a/docs/basic/getting-started/basic-type-examples.md b/docs/basic/getting-started/basic-type-examples.md index a85df10f4..3ec4da51f 100644 --- a/docs/basic/getting-started/basic-type-examples.md +++ b/docs/basic/getting-started/basic-type-examples.md @@ -91,7 +91,7 @@ export declare interface AppProps { childrenElement: React.JSX.Element; // A single React element style?: React.CSSProperties; // to pass through style props onChange?: React.FormEventHandler; // form events! the generic parameter is the type of event.target - // more info: https://react-typescript-cheatsheet.netlify.app/docs/advanced/patterns_by_usecase/#wrappingmirroring + // more info: https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/patterns_by_usecase/#wrappingmirroring props: Props & React.ComponentPropsWithoutRef<"button">; // to impersonate all the props of a button element and explicitly not forwarding its ref props2: Props & React.ComponentPropsWithRef; // to impersonate all the props of MyButtonForwardedRef and explicitly forwarding its ref } @@ -109,8 +109,6 @@ Quote [@ferdaber](https://github.com/typescript-cheatsheets/react/issues/57): A [More discussion: Where ReactNode does not overlap with React.JSX.Element](https://github.com/typescript-cheatsheets/react/issues/129) -[Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new). - ## Types or Interfaces? You can use either Types or Interfaces to type Props and State, so naturally the question arises - which do you use? @@ -158,5 +156,3 @@ It's a nuanced topic, don't get too hung up on it. Here's a handy table: ⚠️ In some cases (source: [Karol Majewski](https://twitter.com/karoljmajewski/status/1082413696075382785)) - -[Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new). diff --git a/docs/basic/getting-started/class-components.md b/docs/basic/getting-started/class-components.md index bbffaf9d9..8c1113818 100644 --- a/docs/basic/getting-started/class-components.md +++ b/docs/basic/getting-started/class-components.md @@ -106,8 +106,6 @@ class App extends React.Component<{ [View in the TypeScript Playground](https://www.typescriptlang.org/play/?jsx=2#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wFgAoCtAGxQGc64BBMMOJADxiQDsATRsnQwAdAGFckHrxgAeAN4U4cEEgYoA5kgBccOjCjAeGgNwUAvgD44i8sshHuUXTwCuIAEZIoJuAHo-OGpgAGskOBgAC2A6JTg0SQhpHhgAEWA+AFkIVxSACgBKGzjlKJiRBxTvOABeOABmMzs4cziifm9C4ublIhhXKB44PJLlOFk+YAA3S1GxmzK6CpwwJdV1LXM4FH4F6KXKp1aesdk-SZnRgqblY-MgA) -[Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new). - ## Typing getDerivedStateFromProps Before you start using `getDerivedStateFromProps`, please go through the [documentation](https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops) and [You Probably Don't Need Derived State](https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html). Derived State can be implemented using hooks which can also help set up memoization. diff --git a/docs/basic/getting-started/concurrent.md b/docs/basic/getting-started/concurrent.md index 07e4f6bb4..c1c012175 100644 --- a/docs/basic/getting-started/concurrent.md +++ b/docs/basic/getting-started/concurrent.md @@ -149,5 +149,3 @@ The standalone version does not provide an `isPending` flag — use the hook if - [`useActionState`, `useFormStatus`, `useOptimistic`](https://react.dev/reference/react) — built on top of transitions - [Server Components and `'use server'`](https://react.dev/reference/rsc/server-components) - -[Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new). diff --git a/docs/basic/getting-started/default-props.md b/docs/basic/getting-started/default-props.md index b29bbdf91..e403ad423 100644 --- a/docs/basic/getting-started/default-props.md +++ b/docs/basic/getting-started/default-props.md @@ -77,5 +77,3 @@ export type ApparentGreetProps = React.JSX.LibraryManagedAttributes< For most apps this isn't needed — only library authors who re-export the props type tend to hit it. - -[Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new). diff --git a/docs/basic/getting-started/error-boundaries.md b/docs/basic/getting-started/error-boundaries.md index cdf0726e6..5163fe100 100644 --- a/docs/basic/getting-started/error-boundaries.md +++ b/docs/basic/getting-started/error-boundaries.md @@ -49,5 +49,3 @@ class ErrorBoundary extends Component { export default ErrorBoundary; ``` - -[Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new). diff --git a/docs/basic/getting-started/forward-create-ref.md b/docs/basic/getting-started/forward-create-ref.md index aba5485df..bfba4de73 100644 --- a/docs/basic/getting-started/forward-create-ref.md +++ b/docs/basic/getting-started/forward-create-ref.md @@ -52,7 +52,7 @@ function Parent() { } ``` -**Read more**: [Wrapping/Mirroring a HTML Element](/docs/advanced/patterns_by_usecase#wrappingmirroring-a-html-element) +**Read more**: [Wrapping/Mirroring a HTML Element](/docs/basic/getting-started/patterns_by_usecase#wrappingmirroring-a-html-element) ## Legacy Approaches (Pre-React 19) diff --git a/docs/basic/getting-started/hooks.md b/docs/basic/getting-started/hooks.md index ea8bb195e..46a23b578 100644 --- a/docs/basic/getting-started/hooks.md +++ b/docs/basic/getting-started/hooks.md @@ -405,5 +405,3 @@ If you are writing a React Hooks library, don't forget that you should also expo - https://github.com/mweststrate/use-st8 - https://github.com/palmerhq/the-platform - https://github.com/sw-yx/hooks - -[Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new). diff --git a/docs/advanced/patterns_by_usecase.md b/docs/basic/getting-started/patterns_by_usecase.md similarity index 99% rename from docs/advanced/patterns_by_usecase.md rename to docs/basic/getting-started/patterns_by_usecase.md index 9127415e6..3124e6e3e 100644 --- a/docs/advanced/patterns_by_usecase.md +++ b/docs/basic/getting-started/patterns_by_usecase.md @@ -65,8 +65,6 @@ export interface ButtonProps extends React.ButtonHTMLAttributes Note: There are over 50 of these specialized interfaces available - look for `HTMLAttributes` in our [`@types/react` commentary](https://react-typescript-cheatsheet.netlify.app/docs/advanced/types_react_api#typesreact). - Ultimately, [we picked the `ComponentProps` method](https://github.com/typescript-cheatsheets/react/pull/276) as it involves the least TS specific jargon and has the most ease of use. But you'll be fine with either of these methods if you prefer. ### Definitely not `React.HTMLProps` or `React.HTMLAttributes` diff --git a/docs/basic/linting.md b/docs/basic/linting.md deleted file mode 100644 index 9cdb407b4..000000000 --- a/docs/basic/linting.md +++ /dev/null @@ -1,101 +0,0 @@ ---- -id: linting -title: Linting ---- - -Follow the TypeScript + ESLint docs at https://github.com/typescript-eslint/typescript-eslint: - -``` -yarn add -D @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint -``` - -add a `lint` script to your `package.json`: - -```json - "scripts": { - "lint": "eslint 'src/**/*.ts'" - }, -``` - -and a suitable `.eslintrc.js` (using `.js` over `.json` here so we can add comments): - -```js -module.exports = { - 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 }, - ], - "@typescript-eslint/explicit-function-return-type": "warn", // Consider using explicit annotations for object literals and function return types even when they can be inferred. - "no-empty": "warn", - }, -}; -``` - -Most of this is taken from [the `tsdx` PR](https://github.com/palmerhq/tsdx/pull/70/files) which is for **libraries**. - -More `.eslintrc.json` options to consider with more options you may want for **apps**: - -```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" - } - } - ] -} -``` - -Another great resource is ["Using ESLint and Prettier in a TypeScript Project"](https://dev.to/robertcoopercode/using-eslint-and-prettier-in-a-typescript-project-53jb) by @robertcoopercode. - -Wes Bos is also working on [TypeScript support for his eslint+prettier config.](https://github.com/wesbos/eslint-config-wesbos/issues/68) - -If you're looking for information on Prettier, check out the [Prettier](https://github.com/typescript-cheatsheets/react/blob/main/docs/advanced/misc-concerns.md#prettier) guide. diff --git a/docs/hoc/excluding-props.md b/docs/hoc/excluding-props.md deleted file mode 100644 index 42a89a3f1..000000000 --- a/docs/hoc/excluding-props.md +++ /dev/null @@ -1,131 +0,0 @@ ---- -id: excluding_props -sidebar_label: Excluding Props -title: "Section 2: Excluding Props" ---- - -This is covered in passing in Section 1 but we focus on it here as it is such a common issue. HOCs often inject props to premade components. The problem we want to solve is having the HOC-wrapped-component exposing a type that reflects the reduced surface area of props - without manually retyping the HOC every time. This involves some generics, fortunately with some helper utilities. - -Say we have a component: - -```tsx -type DogProps { - name: string - owner: string -} -function Dog({name, owner}: DogProps) { - return
Woof: {name}, Owner: {owner}
-} -``` - -And we have a `withOwner` HOC that injects the `owner`: - -```tsx -const OwnedDog = withOwner("swyx")(Dog); -``` - -We want to type `withOwner` such that it will pass through the types of any component like `Dog`, into the type of `OwnedDog`, minus the `owner` property it injects: - -```tsx -typeof OwnedDog; // we want this to be equal to { name: string } - -; // this should be fine -; // this should have a typeError -; // this should be fine - -// and the HOC should be reusable for completely different prop types! - -type CatProps = { - lives: number; - owner: string; -}; -function Cat({ lives, owner }: CatProps) { - return ( -
- {" "} - Meow: {lives}, Owner: {owner} -
- ); -} - -const OwnedCat = withOwner("swyx")(Cat); - -; // this should be fine -; // this should have a typeError -; // this should be fine -``` - -So how do we type `withOwner`? - -1. We get the types of the component: `keyof T` -2. We `Exclude` the property we want to mask: `Exclude`, this leaves you with a list of names of properties you want on the wrapped component e.g. `name` -3. (optional) Use intersection types if you have more to exclude: `Exclude` -4. Names of properties aren't quite the same as properties themselves, which also have an associated type. So we use this generated list of names to `Pick` from the original props: `Pick>`, this leaves you with the new, filtered props, e.g. `{ name: string }` -5. (optional) Instead of writing this manually each time, we could use this utility: `type Omit = Pick>` -6. Now we write the HOC as a generic function: - -```tsx -function withOwner(owner: string) { - return function ( - Component: React.ComponentType - ) { - return function (props: Omit): React.JSX.Element { - const newProps = { ...props, owner } as T; - return ; - }; - }; -} -``` - -(_[Link to TS Playground](https://www.typescriptlang.org/play/?strictFunctionTypes=false&jsx=1&ssl=1&ssc=1&pln=47&pc=49#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgIilQ3wG4AoczAVwDsNgJa4B3YGACwHkXakoAFBF78AXHADOMKMFoBzAJRwA3uThwiMalGY16MRswA8AFThIAHjCS0AJhJVxhfKOKkz5cAL4A+AWvU4AGFcSD5aGHFkdBgAOhDwJhsYEwBPMCRTHwClVUCNJC0dOD0GJjgBMBwwCXEuEHZTABoCZ358HyVxACkAZQANWIBRABskEGSVAPyAehmAQTgYdKQ4NAh+NEM4YAc+NDQkCQkUKFS4ACMkNBRqCVW0jN60GTB4Ww2JWgByeABrWjCJYcFDwTireqNEwtfBtKAdOAAahUcPEsXRXjgAF44CZpoF1rQpHA+CwAArVBw45RwdGxKoQGotOHeOAoBwmCj5dSabTGBJhSbKOmkimMiSYmY+LmBLwyuXkLyUZYZYKgsU1bFTdQjYAANyO4lo1BAVygMtRkmksjkFAVpQM5SCoIENN1BokzJEUG84mdMA1ElyAV5xX8+SMtn12W5KnwBCVsYAskhhOJlO6jl4WjwXOm4YnAkYZlG9TG4Ao7ZRCcTc0hbP6tWxOHXBPgJCxUhZ8AoBP7K5QjI3MxIscoAJyYuFY9ud7twKWkBczYG7SQcCDUEa2S6rTCyJDkIx1huguAjseTpzemcdrvxxfL1cOCQbrc7kEGtlLFZDKA4KAjxPYd9SOS9JWlJ9ODXV9N23XcSgPShyBVVYABEIDkQNtRJFAJjca15ACS13BtRUqDoMpmAwuRXVoPCkC9FwvHEGjA2DHlCj5OBI2jOAAHUIAgTB03oiZszgVt829Lxi1LbIlRreATxopt2G4b0BFne9exogdB1UsSkBnfcPnjadtPnR85mfdc4J3K5EL4ICRFsQyGJM4AzOvFxbznB9IJs6CXzfeDP1WFAfwyP8AJcvg3Mw3CJk87zrJXYK7PfBD9z4IA)_) - -Note that we need to do a type coercion here. - -This is because TypeScript does not know that merging `Omit` and `{owner: "whatever"}` is the same as `T`. - -[See this GitHub issue for more.](https://github.com/microsoft/TypeScript/issues/35858) - -## Generic solution - -The above snippet can be modified to create a generic solution to inject any arbitrary props; - -```typescript -function withInjectedProps>( - injectedProps: U -) { - return function (Component: React.ComponentType) { - return function (props: Omit): React.JSX.Element { - //A type coercion is necessary because TypeScript doesn't know that the Omit + {...injectedProps} = T - const newProps = { ...props, ...injectedProps } as T; - return ; - }; - }; -} -``` - -(_[Link to TS Playground](https://www.typescriptlang.org/play?strictFunctionTypes=false&jsx=1#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgIilQ3wG4AoczAVwDsNgJa4B3YGACwElaArJDEgAmABRxgAzgB4AqnCQAPGElpCJiAdCFSJMKMFoBzADRw6Aa1oQWtAHy24ACgP9Bo8RIBccGQEo4AN7kcHBEMNRQzDT0MIzMUgAq8koqaj62jsEhcADCuJC0KjDeyOgwAHR54ExFCQCeYEiJtln+QdmhSOGRcNEMTE5gHt4A8iDsiabmSHUQmOn+3gBSAMoAGuUAogA2SCBFgVkdAPTHAIJwMA1IcGgQSFBocXDA6oVoaEgSEihQdXAAIwEKGoEhu9UaKzQ+jA8CE9wktAA5PBLNZLhwUPBODcxhMEqZ8NZClB8A4ANSBYkPbzlOkAXzgAF44Akjtk7rRdHBCiwxBBJMzAnA6eUhgKJKZRS4BMp3BK4IyUOoEhQOiEwhF4lUCgcAqLefzJIzjrY1dl6ebLeR6ZQro1clijeoWe04NtgAA3L7eWjUEBAqDm6lQby6fRGCjWvqxAY5LGOALur1fUwhxXeeMwZ1tLKanqZDpSIRelrqwL4Ai28sAWSQ1m8AQ93ok9NMIxsNKpnag1eyUmOJc9ZbgvijduucBE2xQhWzHiFbtoKH2Yb0BkMpDgNsoMee09nXUTy-2jO8B7nOcOGq6Wqc7OLpbgjSgEiYbxXN1egRPSHpA6HEcx23W1yE5bkO0KIQsyFNhOB4Vw5WdRMQ28fAAQgAF8HpXxHCzYDKCkGDmy+JkAgATkZEMmXwCQWDqBRK1NLdTgxb8JA4CBqG2IRARuTADCQcgpEg4RiJTCQyMouBqNo+jGLgZjFOONj1A4rieLgTFvTgFBLmuTYoBwKBhNE6CsWTFspJNM1lNUuB1O43igV6QTKHA+AzIvLpYPYbg+FlYRkICVCCAwrCcMcbyYGA1jNgURo3HkIzoDgABaXTtk4LjDA4Ux2CRN4IHgMBfliNBuN+bZ-iIFAhBQAFdnKbcgA)_) - -## Without coercion - -```typescript -function withOwner(owner: string) { - return function ( - Component: React.ComponentType - ): React.ComponentType & { owner?: never }> { - return function (props) { - const newProps = { ...props, owner }; - return ; - }; - }; -} -``` - -(_[Link to TS Playground](https://www.typescriptlang.org/play?strictFunctionTypes=false&jsx=1#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgIilQ3wG4AoczAVwDsNgJa4B3YGACwHkXakoAFBF78AXHADOMKMFoBzAJRwA3uThwiMalGY16MRswA8AFThIAHjCS0AJhJVxhfKOKkz5cAL4A+AWvU4AGFcSD5aGHFkdBgAOhDwJhsYEwBPMCRTHwCFKOI4hLDktIyjLhB2UwAaAmd+fB84ADIVOqgAfnE+ADd+XxUA9U1tXToGJjgBMBwwCSVVQMC0Jik4PhYABRmHAF5HWIPpiFmatu8KRaGkLR04I0KkiJUD2PWt44kvOAB6HwvArz-QHkLyUGDpJDBFAwd6zOB7BZwAA2wF6Ei61BAACN+P82m5pLI5BRgXpxswgtCBMpkaikBJTiIoN5xJSYdt5gFhrd-IsjLZUdlLip8ARQcKALJIYTiZQotFeGo8FyytriwJGb4C7pCuAKEmUZa0VbKpC2Nnw1jsbhMgT4CQsVIWfAKARs-WUe7Q2lonbKACcXzaO3tjudPz+P2+cE4wAcEg4EGoSNscBxcEwsiQ5DKInN3vl9L9gacTJDDqdot+pCjMY4cckieTqY4KF6cBQMYhAFEoDgoDnTfn4IWJMWvtXa7H402U2nIZm+JRyOCMnAACIQOSwhyI2goEBIAkeOQBfGSQnyEFUMYGCabuTU-eHxkuLziB87zlXG7GbWNAB1CAIEwWVnyQRU4FNVxWiZLxNX-a8jRNPMH0tNhOGgu0K2dV0Hw9T00PAkNM1sCBRWDUNKwjGtvmjadGyTOd00XbNcz4WwiIPJASOAMiKLLKjw0nOi6wbBMmJbNtIU7VckF7ftB1Qrc1m43j+Joqd6xnST5wzLMgA)_) - -## Learn More - -We will need to extract lessons from here in future but here they are: - -- https://medium.com/@xfor/typescript-react-hocs-context-api-cb46da611f12 -- https://medium.com/@jrwebdev/react-higher-order-component-patterns-in-typescript-42278f7590fb -- https://www.matthewgerstman.com/tech/ts-tricks-higher-order-components/ diff --git a/docs/hoc/full-example.md b/docs/hoc/full-example.md deleted file mode 100644 index 23eed5108..000000000 --- a/docs/hoc/full-example.md +++ /dev/null @@ -1,99 +0,0 @@ ---- -id: full_example -sidebar_label: Full HOC Example -title: "Full HOC Example" ---- - -> This is an HOC example for you to copy and paste. If certain pieces don't make sense for you, head to [the React HOC Docs intro](https://react-typescript-cheatsheet.netlify.app/docs/hoc/react_hoc_docs/) to get a detailed walkthrough via a complete translation of the React docs in TypeScript. - -Sometimes you want a simple way to inject props from somewhere else (either a global store or a provider) and don't want to continually pass down the props for it. Context is great for it, but then the values from the context can only be used in your `render` function. A HoC will provide these values as props. - -**The injected props** - -```ts -interface WithThemeProps { - primaryColor: string; -} -``` - -**Usage in the component** - -The goal is to have the props available on the interface for the component, but subtracted out for the consumers of the component when wrapped in the HoC. - -```ts -interface Props extends WithThemeProps { - children?: React.ReactNode; -} - -class MyButton extends React.Component { - public render() { - // Render an the element using the theme and other props. - } - - private someInternalMethod() { - // The theme values are also available as props here. - } -} - -export default withTheme(MyButton); -``` - -**Consuming the Component** - -Now when consuming the component you can omit the `primaryColor` prop or override the one provided through context. - -```tsx -Hello button // Valid -Hello Button // Also valid -``` - -**Declaring the HoC** - -The actual HoC. - -```tsx -export function withTheme( - WrappedComponent: React.ComponentType -) { - // Try to create a nice displayName for React Dev Tools. - const displayName = - WrappedComponent.displayName || WrappedComponent.name || "Component"; - - // Creating the inner component. The calculated Props type here is the where the magic happens. - const ComponentWithTheme = (props: Omit) => { - // Fetch the props you want to inject. This could be done with context instead. - const themeProps = useTheme(); - - // props comes afterwards so the can override the default ones. - return ; - }; - - ComponentWithTheme.displayName = `withTheme(${displayName})`; - - return ComponentWithTheme; -} -``` - -Note that the `{...(props as T)}` assertion is needed because of a current bug in TS 3.2 https://github.com/Microsoft/TypeScript/issues/28938#issuecomment-450636046 - -Here is a more advanced example of a dynamic higher order component that bases some of its parameters on the props of the component being passed in: - -```tsx -// inject static values to a component so that they're always provided -export function inject( - Component: React.JSXElementConstructor, - injector: Pick -) { - return function Injected(props: Omit) { - return ; - }; -} -``` - -### Using `forwardRef` - -For "true" reusability you should also consider exposing a ref for your HOC. You can use `React.forwardRef` as documented in [the basic cheatsheet](https://github.com/typescript-cheatsheets/react/blob/main/README.md#forwardrefcreateref), but we are interested in more real world examples. [Here is a nice example in practice](https://gist.github.com/OliverJAsh/d2f462b03b3e6c24f5588ca7915d010e) from @OliverJAsh (note - it still has some rough edges, we need help to test this out/document this). - -### Supporting `defaultProps` of Wrapped Component - -If this is something you need, please see [the stale discussion we had](https://github.com/typescript-cheatsheets/react/issues/86) and comment with your requirements. We will pick this up again if needed. diff --git a/docs/hoc/index.md b/docs/hoc/index.md deleted file mode 100644 index 5803667e0..000000000 --- a/docs/hoc/index.md +++ /dev/null @@ -1,65 +0,0 @@ ---- -id: intro -sidebar_label: Intro -title: HOC Cheatsheet ---- - -**This HOC Cheatsheet** compiles all available knowledge for writing Higher Order Components with React and TypeScript. - -- We will map closely to [the official docs on HOCs](https://reactjs.org/docs/higher-order-components.html) initially -- While hooks exist, many libraries and codebases still have a need to type HOCs. -- Render props may be considered in the future -- The goal is to write HOCs that offer type safety while not getting in the way. - -There are a lot of use cases where an HOC is used. For example: - -- HOCs can wrap components to check if a user is authenticated before rendering, or to restrict access based on user roles. -- An HOC can conditionally render components based on feature flags or A/B testing. -- An HOC can provide translation functionality to components. -- An HOC can add logging or analytics tracking to components without modifying their core logic. - -Here is a base HOC example you can copy right away: - -```tsx -type PropsAreEqual

= ( - prevProps: Readonly

, - nextProps: Readonly

-) => boolean; - -const withSampleHoC =

( - component: { - (props: P): Exclude; - displayName?: string; - }, - propsAreEqual?: PropsAreEqual

| false, - - componentName = component.displayName ?? component.name -): { - (props: P): React.JSX.Element; - displayName: string; -} => { - function WithSampleHoc(props: P) { - //Do something special to justify the HoC. - return component(props) as React.JSX.Element; - } - - WithSampleHoc.displayName = `withSampleHoC(${componentName})`; - - let wrappedComponent = - propsAreEqual === false - ? WithSampleHoc - : React.memo(WithSampleHoc, propsAreEqual); - - //copyStaticProperties(component, wrappedComponent); - - return wrappedComponent as typeof WithSampleHoc; -}; -``` - -This code meets these criteria: - -1. Allows a component to return valid elements (`strings | array | boolean | null | number`) and not just `React.JSX.Element | null`. -2. Wraps it in a memo unless you opt out. -3. Removes the nested component, so React Dev tools will just show one component. -4. Indicates with `displayName` in React Dev Tool with an annotation that this is a component wrapped in two HoCs -5. Optional: Copies over static properties that might have been defined on the original component. diff --git a/docs/hoc/react-hoc-docs.md b/docs/hoc/react-hoc-docs.md deleted file mode 100644 index 6a099dd05..000000000 --- a/docs/hoc/react-hoc-docs.md +++ /dev/null @@ -1,297 +0,0 @@ ---- -id: react_hoc_docs -sidebar_label: React HOC docs in TypeScript -title: "Section 1: React HOC docs in TypeScript" ---- - -In this first section we refer closely to [the React docs on HOCs](https://reactjs.org/docs/higher-order-components.html) and offer direct TypeScript parallels. - -## Docs Example: [Use HOCs For Cross-Cutting Concerns](https://reactjs.org/docs/higher-order-components.html#use-hocs-for-cross-cutting-concerns) - -

- - -Misc variables referenced in the example below - - -```tsx -/** dummy child components that take anything */ -const Comment = (_: any) => null; -const TextBlock = Comment; - -/** dummy Data */ -type CommentType = { text: string; id: number }; -const comments: CommentType[] = [ - { - text: "comment1", - id: 1, - }, - { - text: "comment2", - id: 2, - }, -]; -const blog = "blogpost"; - -/** mock data source */ -const DataSource = { - addChangeListener(e: Function) { - // do something - }, - removeChangeListener(e: Function) { - // do something - }, - getComments() { - return comments; - }, - getBlogPost(id: number) { - return blog; - }, -}; -/** type aliases just to deduplicate */ -type DataType = typeof DataSource; -// type TODO_ANY = any; - -/** utility types we use */ -type Omit = Pick>; -// type Optionalize = Omit; - -/** Rewritten Components from the React docs that just uses injected data prop */ -function CommentList({ data }: WithDataProps) { - return ( -
- {data.map((comment: CommentType) => ( - - ))} -
- ); -} -interface BlogPostProps extends WithDataProps { - id: number; -} -function BlogPost({ data, id }: BlogPostProps) { - return ( -
- ; -
- ); -} -``` - -[View in TypeScript Playground](https://www.typescriptlang.org/play/?jsx=2#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wFgAoCgeirhgAskBnJOFIuxuMHMJuiHABGrYADsAVkgxIAJsICenVgAkA8gGEK4mEiiZ0rAOrAGAERQwUABV5MAPABUAfHADeFOHFmWUALjhHAG44Gm9fOGB+AHMkMT1gNAoAX2paR0j+BlYYBTBWCExwqzS4a0zlbjs4QsqAdygUMHz5NFxIeLF4BksK8Uw9IllSjQrstgwAVxQAG0iuvQM0AqLxhqaWuDbwCE74AApJlnkYQWjGoW8kA0mZmFsIPjhsXEiYAEoKJAAPSFhnyZiDDAXZwOqmegAZUmQiYaCgwDAMBBYicABoynAfroxLJ+CZzL4HnwnM4MRpnPtPKFaAwonQ8qxZjMIHV+EcBPMBlAyhihJN4OcUJdxrl8jUikZGs05Bp2rs4vAWGB2JYkDMlOCGBABW95rp9AkxNEwRDKv09HFlhKytSpRtZfK9gFkOgYAA6ABSkIAGgBRGZIECKuViJgwKCTDDQezWVwAMjgGjR1LCLEDGAsVgqKABQNOPMw0ECqdoPEe-Hprtkuw1wmkKCOohg+H4RBQNbEdfETGAshWlTQMxQTCY1PT0hgWf8cCp5C8Xh8VkhOqgywCYqQtWnK8ma6QKfnC-LfBdqE7Gvs3p97oAMsAhI0oAoALIoMQoWKyACCMAjD4FZh7GTOA1BAUxYwxAAiJcUCg5wEOpd44AAXlcRwKGQjwjzCcYQE-RIKkYIgAmvO8HyfV930-ORf3-fldH4cEZjmKwAGsci4TcbXtFo5R2PY2FxOAiCYCAZgAN2bfh+xuO4qgrUs2GiFAe26LgT34WoCXoacMTqehEnoCoJCOdSCgRaJxFmTFuK1Yz8Fg-ARKDCApPkF48FMNskAAR0mYAiGDLoxyPbjiX4FC4DI+9H3YKiPy-OiEQYoCQLAiDrGg2D4OcIJqW4yErF0VD3GpRdfACYJqWSfKjyIGA9zELZh1HOAdOnLFvhxPFEGID1+I6RVYzsDEirVVxsIXLZdnDSNoygfZNICCKsPKhcmEmfJFs0946umrw6SYd16HfWRAw0U7jVYKKjpOs6Lqu2J3SEcRZH2I69vWw7DOO8M1VKqaDoqqwAgnTNfH2HdV2WDFdu+uBavW1JKCPLxtiGrozD7F8dS6Ur9mQtC4GhvdlndDtZEu99YnvcM4j0D7fvu3FHpppAvtR6aMYVLoTBYgBVMQQDx+AosJ1DnAR0n93dIK3KQanrrpnFGbuq7zsVp6Obq9aNbZ66CaJqW0YXO6WBgcbdH2IHgdgsH1Unacod8Xd9wxO74dNrxkk59aiFxRm1u9mlKjFcQTSLHkmB4c8I84KJ3U0zJ3VTuApOfGbwEDb53XrcMwRQJRLPoeAxFZMZBFMgvuNMNh+HfBQEbCWDTRYuBw2AduRAZfI0EYNAOOGEOGqa2cEa8exeL4p1FWKFAULcc3iqQd1YOSdxU-dJnE+TkchIUd4N6oE3gc56aUZ9-bQ9HqBmo63w6pR6gACoX7gdRRiOGjTQYJNZ5CnAF+VAvi-GgPANoYZ4D8WCjAFWOloSwnhIiZEoIor2UQXCBESIURzi8DAxUKtDxeBdsuGGSAAjTkcIyY2JNXbkPdLEGABCQqE0wrrcgPw-gQNmvAAAQiyaI1gIDhgQTCLBKCUSlQweI5BODdh4LgAIiAQiREwGIbOGW646FWGofkOGdgAgZRgPYZRqjwwRWyr4eCxt1paNXkwsxwjwxLTsO6PsnxyB7SAA) - -
- -Example HOC from React Docs translated to TypeScript - -```tsx -// these are the props to be injected by the HOC -interface WithDataProps { - data: T; // data is generic -} -// T is the type of data -// P is the props of the wrapped component that is inferred -// C is the actual interface of the wrapped component (used to grab defaultProps from it) -export function withSubscription, C>( - // this type allows us to infer P, but grab the type of WrappedComponent separately without it interfering with the inference of P - WrappedComponent: React.JSXElementConstructor

& C, - // selectData is a functor for T - // props is Readonly because it's readonly inside of the class - selectData: ( - dataSource: typeof DataSource, - props: Readonly>> - ) => T -) { - // the magic is here: React.JSX.LibraryManagedAttributes will take the type of WrapedComponent and resolve its default props - // against the props of WithData, which is just the original P type with 'data' removed from its requirements - type Props = React.JSX.LibraryManagedAttributes>; - type State = { - data: T; - }; - return class WithData extends React.Component { - constructor(props: Props) { - super(props); - this.handleChange = this.handleChange.bind(this); - this.state = { - data: selectData(DataSource, props), - }; - } - - componentDidMount = () => DataSource.addChangeListener(this.handleChange); - - componentWillUnmount = () => - DataSource.removeChangeListener(this.handleChange); - - handleChange = () => - this.setState({ - data: selectData(DataSource, this.props), - }); - - render() { - // the typing for spreading this.props is... very complex. best way right now is to just type it as any - // data will still be typechecked - return ( - - ); - } - }; - // return WithData; -} - -/** HOC usage with Components */ -export const CommentListWithSubscription = withSubscription( - CommentList, - (DataSource: DataType) => DataSource.getComments() -); - -export const BlogPostWithSubscription = withSubscription( - BlogPost, - (DataSource: DataType, props: Omit) => - DataSource.getBlogPost(props.id) -); -``` - -## Docs Example: [Don’t Mutate the Original Component. Use Composition.](https://reactjs.org/docs/higher-order-components.html#dont-mutate-the-original-component-use-composition) - -This is pretty straightforward - make sure to assert the passed props as `T` [due to the TS 3.2 bug](https://github.com/Microsoft/TypeScript/issues/28938#issuecomment-450636046). - -```tsx -function logProps(WrappedComponent: React.ComponentType) { - return class extends React.Component { - componentWillReceiveProps( - nextProps: React.ComponentProps - ) { - console.log("Current props: ", this.props); - console.log("Next props: ", nextProps); - } - render() { - // Wraps the input component in a container, without mutating it. Good! - return ; - } - }; -} -``` - -## Docs Example: [Pass Unrelated Props Through to the Wrapped Component](https://reactjs.org/docs/higher-order-components.html#convention-pass-unrelated-props-through-to-the-wrapped-component) - -No TypeScript specific advice needed here. - -## Docs Example: [Maximizing Composability](https://reactjs.org/docs/higher-order-components.html#convention-maximizing-composability) - -HOCs can take the form of Functions that return Higher Order Components that return Components. - -`connect` from `react-redux` has a number of overloads you can take inspiration [from in the source](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/bc0c933415466b34d2de5790f7cd6418f676801e/types/react-redux/v5/index.d.ts#L77). - -Here we build our own mini `connect` to understand HOCs: - -

- - -Misc variables referenced in the example below - - -```tsx -/** utility types we use */ -type Omit = Pick>; - -/** dummy Data */ -type CommentType = { text: string; id: number }; -const comments: CommentType[] = [ - { - text: "comment1", - id: 1, - }, - { - text: "comment2", - id: 2, - }, -]; -/** dummy child components that take anything */ -const Comment = (_: any) => null; -/** Rewritten Components from the React docs that just uses injected data prop */ -function CommentList({ data }: WithSubscriptionProps) { - return ( -
- {data.map((comment: CommentType) => ( - - ))} -
- ); -} -``` - -
- -```tsx -const commentSelector = (_: any, ownProps: any) => ({ - id: ownProps.id, -}); -const commentActions = () => ({ - addComment: (str: string) => - comments.push({ text: str, id: comments.length }), -}); - -const ConnectedComment = connect(commentSelector, commentActions)(CommentList); - -// these are the props to be injected by the HOC -interface WithSubscriptionProps { - data: T; -} -function connect(mapStateToProps: Function, mapDispatchToProps: Function) { - return function , C>( - WrappedComponent: React.ComponentType - ) { - type Props = React.JSX.LibraryManagedAttributes>; - // Creating the inner component. The calculated Props type here is the where the magic happens. - return class ComponentWithTheme extends React.Component { - public render() { - // Fetch the props you want inject. This could be done with context instead. - const mappedStateProps = mapStateToProps(this.state, this.props); - const mappedDispatchProps = mapDispatchToProps(this.state, this.props); - // this.props comes afterwards so the can override the default ones. - return ( - - ); - } - }; - }; -} -``` - -[View in TypeScript Playground](https://www.typescriptlang.org/play/?jsx=2#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wFgAoCtCAOwGd5qQQkaY64BeOAbQF0A3BSq0GcAMK4WbADLAx3ABQBKLgD44iinDgAeACbAAbnAD0aisuHlq9RlNYwAykgA2SDNC6aA+gC44FBoATwAaOAgAdxoABRwwOgCg4NVODUUAb204YH0AqNj4ugA6XIoAX2UhG1F7ZkcAQQxgUW8VdU0s8h0UfX1JerYAxQYoANHgGgBzVI0maXZisABXOgALTLgYJAAPGHGYKHDcgPnHEvdpmDW4Soqq61sxSRoaD23+hzZvWzeMLW6cDObBc7k8R2ywJgTRgLXolkUAwWcgYD0o5FMpi2ayQdCQgSI2PxYCKWwgcAARvjJgArd5IfSU4JEuAACQA8uIKJNtlBMOh8QB1YDXJzLCl0NBQYBgWG0OIQBK6AAqGi6On0KBgKACyuq5QomGWNGatCBtD+MEUIBQYCc2u2yogCoSAQAYsbTTRwjawAAReRgLVoNZOl2JOAek1ymiqdVwIgwZZQGhwI3RuEq8IxOC7bY0fQcYWi8WS6WyuHhlVqcLiNQAnQ6QVQW1gBkDSBvIaIYgwYod2iOZXBNvV7Jx7I6GAj-Hh7wAKScAA1inIKS2oMEALJBFBTBkNGCHYAU5bbOi6cThdkgEW6GLhABEmu1j7UamqjbMWPERC1kymFlJjeKBzXAQc2GKOBlRxIEUFcNBllcLUGTgOdpzbOAcUJeQWUibD8WufEbSmYA0Cw1tWBKScEyQJMUyBZC6A4AcuxgYtQxxFhcz2VhCx7dA+1Yxx7yKNUaJ0FYKVcMjaILJAoHaeMvx0TFIzokMWRJRUOGCCBljgSIgngWl3igmDcOoJDGSpOB9EHQyRRuWxtj2HI7FQfRigkxsnngX0230e0ULnbhfWCx1nSKRRrnkYoGBQ8JYpKbSEjRFTfNqOAAoZAM6CDGAQ1C7LbTygqQzDaLkvih0kCStY4tSuh0oy79sUa0kmFxQJMF5IyoH4uhySIuDUwgIwFOlfRCNg6b+SQ+BB2owEMsTZNUwbVqdF0ZtKM+cC2J8jKMmKU7qqag0Vq2uATtOnKgtq8NLuuxtbuKe6yuDNYnqOxtzF+lqv2extyk-W59SAA) - -## Docs Example: [Wrap the Display Name for Easy Debugging](https://reactjs.org/docs/higher-order-components.html#convention-wrap-the-display-name-for-easy-debugging) - -This is pretty straightforward as well. - -```tsx -interface WithSubscriptionProps { - data: any; -} - -function withSubscription< - T extends WithSubscriptionProps = WithSubscriptionProps, ->(WrappedComponent: React.ComponentType) { - class WithSubscription extends React.Component { - /* ... */ - public static displayName = `WithSubscription(${getDisplayName( - WrappedComponent - )})`; - } - return WithSubscription; -} - -function getDisplayName(WrappedComponent: React.ComponentType) { - return WrappedComponent.displayName || WrappedComponent.name || "Component"; -} -``` - -## Unwritten: [Caveats section](https://reactjs.org/docs/higher-order-components.html#caveats) - -- Don’t Use HOCs Inside the render Method -- Static Methods Must Be Copied Over -- Refs Aren’t Passed Through diff --git a/docs/react-types/index.md b/docs/react-types/index.md deleted file mode 100644 index 4d86ede51..000000000 --- a/docs/react-types/index.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: React Types ---- - -`@types/react` makes some types available that can be very useful. Here's a list in alphabetical order with links to the detailed reference pages. - -- [`ComponentProps`](/docs/react-types/ComponentProps) -- [`CSSProperties`](/docs/react-types/CSSProperties) -- [`ReactNode`](/docs/react-types/ReactNode) -- [`Ref`, `RefObject`, `RefCallback`](/docs/react-types/Ref) diff --git a/docs/react-types/CSSProperties.md b/docs/reference/CSSProperties.md similarity index 100% rename from docs/react-types/CSSProperties.md rename to docs/reference/CSSProperties.md diff --git a/docs/react-types/ComponentProps.md b/docs/reference/ComponentProps.md similarity index 100% rename from docs/react-types/ComponentProps.md rename to docs/reference/ComponentProps.md diff --git a/docs/react-types/ReactNode.md b/docs/reference/ReactNode.md similarity index 97% rename from docs/react-types/ReactNode.md rename to docs/reference/ReactNode.md index 960c427cf..92ad51342 100644 --- a/docs/react-types/ReactNode.md +++ b/docs/reference/ReactNode.md @@ -124,5 +124,3 @@ const MyComponent = () => "hello"; // 👍 explicit const MyComponent = (): React.JSX.Element => hello; ``` - -[Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new). diff --git a/docs/react-types/Ref.md b/docs/reference/Ref.md similarity index 100% rename from docs/react-types/Ref.md rename to docs/reference/Ref.md diff --git a/genReadme.mjs b/genReadme.mjs index 64640b514..cef250f70 100644 --- a/genReadme.mjs +++ b/genReadme.mjs @@ -164,7 +164,6 @@ async function main(argv) { path: "docs/basic/setup.md", withToc: true, relativeHeadingLevel: 1, - prefix: "Section 1: ", }); pendingReadme = await updateSectionWith({ from: currentReadme, @@ -233,14 +232,6 @@ async function main(argv) { name: "concurrent", path: "docs/basic/getting-started/concurrent.md", }); - pendingReadme = await updateSectionWith({ - from: currentReadme, - to: pendingReadme, - name: "linting", - path: "docs/basic/linting.md", - relativeHeadingLevel: 1, - }); - const prettierConfig = await prettier.resolveConfig(readmePath); pendingReadme = await prettier.format(pendingReadme, { ...prettierConfig, diff --git a/package.json b/package.json index 9bdd7b673..cdbe53c0b 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,8 @@ "postinstall": "cd website && yarn", "prepare": "husky", "start": "yarn --cwd website start", - "build": "yarn --cwd website build" + "build": "yarn --cwd website build", + "serve": "yarn --cwd website serve" }, "dependencies": { "front-matter": "^4.0.2", diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index 3a6d7b0d1..75efb842e 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -14,9 +14,9 @@ const setupDoc = "docs/basic/setup"; module.exports = { favicon: "img/icon.png", - title: "React TypeScript Cheatsheets", // Title for your website. + title: "React TypeScript Cheatsheet", // Title for your website. tagline: - "Cheatsheets for experienced React developers getting started with TypeScript", + "A cheatsheet for experienced React developers getting started with TypeScript", url: "https://react-typescript-cheatsheet.netlify.app", // Your website URL baseUrl: "/", projectName: "react-typescript-cheatsheet", @@ -102,14 +102,6 @@ module.exports = { label: "Introduction", to: setupDoc, }, - { - label: "High Order Component (HOC)", - to: "docs/hoc", - }, - { - label: "Advanced Guides", - to: "docs/advanced", - }, ], }, { diff --git a/website/package.json b/website/package.json index 4163c21af..d7da3db54 100644 --- a/website/package.json +++ b/website/package.json @@ -3,6 +3,7 @@ "add-pages-on-site": "node ../copyFile.js", "start": "yarn add-pages-on-site && docusaurus start", "build": "yarn add-pages-on-site && docusaurus build", + "serve": "docusaurus serve", "swizzle": "docusaurus swizzle", "deploy": "yarn add-pages-on-site && docusaurus deploy" }, diff --git a/website/sidebars.json b/website/sidebars.json index 8ae75091e..7490183d4 100644 --- a/website/sidebars.json +++ b/website/sidebars.json @@ -1,38 +1,33 @@ { - "docs": { - "Basic": [ - "basic/setup", - { - "type": "category", - "label": "Getting Started", - "items": [ - "basic/getting-started/basic_type_example", - "basic/getting-started/function_components", - "basic/getting-started/hooks", - "basic/getting-started/class_components", - "basic/getting-started/default_props", - "basic/getting-started/forms_and_events", - "basic/getting-started/context", - "basic/getting-started/forward_and_create_ref", - "basic/getting-started/portals", - "basic/getting-started/error_boundaries", - "basic/getting-started/concurrent" - ] - }, - "basic/linting" - ], - "HOC": [ - "hoc/intro", - "hoc/full_example", - "hoc/react_hoc_docs", - "hoc/excluding_props" - ], - "Advanced": [ - "advanced/intro", - "advanced/utility_types", - "advanced/patterns_by_usecase", - "advanced/misc_concerns", - "advanced/types_react_api" - ] - } + "docs": [ + "basic/setup", + { + "type": "category", + "label": "Learn", + "items": [ + "basic/getting-started/basic_type_example", + "basic/getting-started/function_components", + "basic/getting-started/hooks", + "basic/getting-started/class_components", + "basic/getting-started/default_props", + "basic/getting-started/forms_and_events", + "basic/getting-started/context", + "basic/getting-started/forward_and_create_ref", + "basic/getting-started/portals", + "basic/getting-started/error_boundaries", + "basic/getting-started/concurrent", + "basic/getting-started/patterns_by_usecase" + ] + }, + { + "type": "category", + "label": "API Reference", + "items": [ + "reference/ComponentProps", + "reference/CSSProperties", + "reference/ReactNode", + "reference/Ref" + ] + } + ] } diff --git a/website/src/pages/index.js b/website/src/pages/index.js index 354cf6715..b519a5c23 100644 --- a/website/src/pages/index.js +++ b/website/src/pages/index.js @@ -9,9 +9,9 @@ export default function Home() { const { siteConfig } = useDocusaurusContext(); return (