├── .all-contributorsrc ├── .dockerignore ├── .github ├── ISSUE_TEMPLATE │ ├── advanced-cheatsheet.md │ ├── basic-cheatsheet.md │ ├── general-react-ts-question.md │ ├── hoc-cheatsheet.md │ └── migrating-cheatsheet.md ├── pull_request_template.md ├── stale.yml └── workflows │ ├── main.yml │ └── mlc_config.json ├── .gitignore ├── .husky └── pre-commit ├── .nvmrc ├── CONTRIBUTING.md ├── CONTRIBUTORS.md ├── LICENSE ├── README.md ├── code-of-conduct.md ├── copyFile.js ├── docs ├── advanced │ ├── index.md │ ├── misc-concerns.md │ ├── patterns_by_usecase.md │ ├── patterns_by_version.md │ ├── types-react-ap.md │ └── utility-types.md ├── basic │ ├── editor-integration.md │ ├── examples.md │ ├── getting-started │ │ ├── basic-type-examples.md │ │ ├── class-components.md │ │ ├── concurrent.md │ │ ├── context.md │ │ ├── default-props.md │ │ ├── error-boundaries.md │ │ ├── forms-and-events.md │ │ ├── forward-create-ref.md │ │ ├── function-components.md │ │ ├── hooks.md │ │ └── portals.md │ ├── linting.md │ ├── recommended │ │ ├── codebases.md │ │ ├── resources.md │ │ └── talks.md │ ├── setup.md │ └── troubleshooting │ │ ├── learn-ts.md │ │ ├── non-ts-files.md │ │ ├── official-typings-bugs.md │ │ ├── operators.md │ │ ├── ts-config.md │ │ ├── types.md │ │ └── utilities.md ├── hoc │ ├── excluding-props.md │ ├── full-example.md │ ├── index.md │ └── react-hoc-docs.md ├── migration │ ├── from-flow.md │ ├── from-js.md │ ├── index.md │ └── js-docs.md └── react-types │ ├── ComponentProps.md │ ├── ReactNode.md │ └── index.md ├── genReadme.js ├── netlify.toml ├── package.json ├── website ├── README.md ├── docusaurus.config.js ├── package.json ├── sidebars.json ├── src │ ├── css │ │ └── custom.css │ └── pages │ │ ├── help.js │ │ ├── index.js │ │ └── users.js ├── static │ └── img │ │ ├── favicon.ico │ │ ├── icon.png │ │ ├── oss_logo.png │ │ ├── undraw_code_review.svg │ │ ├── undraw_monitor.svg │ │ ├── undraw_note_list.svg │ │ ├── undraw_online.svg │ │ ├── undraw_open_source.svg │ │ ├── undraw_operating_system.svg │ │ ├── undraw_react.svg │ │ ├── undraw_tweetstorm.svg │ │ └── undraw_youtube_tutorial.svg └── yarn.lock └── yarn.lock /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "CONTRIBUTORS.md", 4 | "README.md" 5 | ], 6 | "imageSize": 100, 7 | "commit": true, 8 | "commitConvention": "angular", 9 | "contributors": [ 10 | { 11 | "login": "ferdaber", 12 | "name": "Ferdy Budhidharma", 13 | "avatar_url": "https://avatars2.githubusercontent.com/u/12239873?v=4", 14 | "profile": "https://github.com/ferdaber", 15 | "contributions": [ 16 | "review", 17 | "maintenance", 18 | "content" 19 | ] 20 | }, 21 | { 22 | "login": "sw-yx", 23 | "name": "swyx", 24 | "avatar_url": "https://avatars1.githubusercontent.com/u/6764957?v=4", 25 | "profile": "https://twitter.com/swyx", 26 | "contributions": [ 27 | "ideas", 28 | "review", 29 | "maintenance", 30 | "content", 31 | "question" 32 | ] 33 | }, 34 | { 35 | "login": "eps1lon", 36 | "name": "Sebastian Silbermann", 37 | "avatar_url": "https://avatars3.githubusercontent.com/u/12292047?v=4", 38 | "profile": "https://github.com/eps1lon", 39 | "contributions": [ 40 | "review", 41 | "maintenance", 42 | "content" 43 | ] 44 | }, 45 | { 46 | "login": "Attrash-Islam", 47 | "name": "Islam Attrash", 48 | "avatar_url": "https://avatars0.githubusercontent.com/u/7091543?v=4", 49 | "profile": "https://www.linkedin.com/in/islam-attrash-46703a94/", 50 | "contributions": [ 51 | "maintenance", 52 | "content" 53 | ] 54 | }, 55 | { 56 | "login": "stephenkoo", 57 | "name": "Stephen Koo", 58 | "avatar_url": "https://avatars2.githubusercontent.com/u/18624246?v=4", 59 | "profile": "https://stephenkoo.github.io/", 60 | "contributions": [ 61 | "question", 62 | "example" 63 | ] 64 | }, 65 | { 66 | "login": "andreasgruenh", 67 | "name": "Andreas", 68 | "avatar_url": "https://avatars2.githubusercontent.com/u/12122390?v=4", 69 | "profile": "https://github.com/andreasgruenh", 70 | "contributions": [ 71 | "code", 72 | "doc", 73 | "infra" 74 | ] 75 | }, 76 | { 77 | "login": "arvindcheenu", 78 | "name": "Arvind Srinivasan", 79 | "avatar_url": "https://avatars2.githubusercontent.com/u/13925213?v=4", 80 | "profile": "https://github.com/arvindcheenu", 81 | "contributions": [ 82 | "code", 83 | "content", 84 | "doc", 85 | "maintenance" 86 | ] 87 | }, 88 | { 89 | "login": "williamrjribeiro", 90 | "name": "William R. J. Ribeiro", 91 | "avatar_url": "https://avatars2.githubusercontent.com/u/1503499?v=4", 92 | "profile": "http://www.williamrjribeiro.com", 93 | "contributions": [ 94 | "ideas" 95 | ] 96 | }, 97 | { 98 | "login": "alexandrudanpop", 99 | "name": "Alexandru-Dan Pop", 100 | "avatar_url": "https://avatars0.githubusercontent.com/u/15979292?v=4", 101 | "profile": "https://alexandrudanpop.dev/", 102 | "contributions": [ 103 | "doc" 104 | ] 105 | }, 106 | { 107 | "login": "mastorm", 108 | "name": "Mathias Storm", 109 | "avatar_url": "https://avatars1.githubusercontent.com/u/10759336?v=4", 110 | "profile": "https://github.com/mastorm", 111 | "contributions": [ 112 | "doc" 113 | ] 114 | }, 115 | { 116 | "login": "dance2die", 117 | "name": "Sung M. Kim", 118 | "avatar_url": "https://avatars1.githubusercontent.com/u/8465237?v=4", 119 | "profile": "https://twitter.com/dance2die", 120 | "contributions": [ 121 | "doc", 122 | "ideas" 123 | ] 124 | }, 125 | { 126 | "login": "ryota-murakami", 127 | "name": "Ryota Murakami", 128 | "avatar_url": "https://avatars2.githubusercontent.com/u/5501268?v=4", 129 | "profile": "https://ryota-murakami.github.io/", 130 | "contributions": [ 131 | "example", 132 | "doc" 133 | ] 134 | }, 135 | { 136 | "login": "arpi17", 137 | "name": "Árpád Illyés", 138 | "avatar_url": "https://avatars1.githubusercontent.com/u/13800404?v=4", 139 | "profile": "https://github.com/arpi17", 140 | "contributions": [ 141 | "code" 142 | ] 143 | }, 144 | { 145 | "login": "xamgore", 146 | "name": "Igor Strebezhev", 147 | "avatar_url": "https://avatars3.githubusercontent.com/u/4586392?v=4", 148 | "profile": "https://twitter.com/xamgore", 149 | "contributions": [ 150 | "ideas", 151 | "doc" 152 | ] 153 | }, 154 | { 155 | "login": "dwjohnston", 156 | "name": "David Johnston", 157 | "avatar_url": "https://avatars2.githubusercontent.com/u/2467377?v=4", 158 | "profile": "https://geoplanets.io", 159 | "contributions": [ 160 | "doc" 161 | ] 162 | }, 163 | { 164 | "login": "kripod", 165 | "name": "Kristóf Poduszló", 166 | "avatar_url": "https://avatars3.githubusercontent.com/u/14854048?v=4", 167 | "profile": "https://github.com/kripod", 168 | "contributions": [ 169 | "doc" 170 | ] 171 | }, 172 | { 173 | "login": "glaschu1", 174 | "name": "james glasgow", 175 | "avatar_url": "https://avatars3.githubusercontent.com/u/10838852?v=4", 176 | "profile": "http://www.novusstudio.com/", 177 | "contributions": [ 178 | "doc" 179 | ] 180 | }, 181 | { 182 | "login": "Winner95", 183 | "name": "Ivan", 184 | "avatar_url": "https://avatars0.githubusercontent.com/u/13730032?v=4", 185 | "profile": "https://www.linkedin.com/in/iigrekov/", 186 | "contributions": [ 187 | "code" 188 | ] 189 | }, 190 | { 191 | "login": "selrond", 192 | "name": "Sebastian Andil", 193 | "avatar_url": "https://avatars1.githubusercontent.com/u/6603389?v=4", 194 | "profile": "http://sebastianandil.com", 195 | "contributions": [ 196 | "doc" 197 | ] 198 | }, 199 | { 200 | "login": "adnanhusain15", 201 | "name": "Adnan Husain", 202 | "avatar_url": "https://avatars2.githubusercontent.com/u/36721076?v=4", 203 | "profile": "https://github.com/adnanhusain15", 204 | "contributions": [ 205 | "doc" 206 | ] 207 | }, 208 | { 209 | "login": "artola", 210 | "name": "martin", 211 | "avatar_url": "https://avatars0.githubusercontent.com/u/11500763?v=4", 212 | "profile": "https://github.com/artola", 213 | "contributions": [ 214 | "doc" 215 | ] 216 | }, 217 | { 218 | "login": "filiptammergard", 219 | "name": "Filip Tammergård", 220 | "avatar_url": "https://avatars.githubusercontent.com/u/44197016?v=4", 221 | "profile": "https://tammergard.se", 222 | "contributions": [ 223 | "doc", 224 | "code" 225 | ] 226 | }, 227 | { 228 | "login": "jsjoeio", 229 | "name": "Joe Previte", 230 | "avatar_url": "https://avatars.githubusercontent.com/u/3806031?v=4", 231 | "profile": "https://englishbyte.com", 232 | "contributions": [ 233 | "doc" 234 | ] 235 | }, 236 | { 237 | "login": "sasirura", 238 | "name": "Sasiru Ravihansa", 239 | "avatar_url": "https://avatars.githubusercontent.com/u/42542164?v=4", 240 | "profile": "https://github.com/sasirura", 241 | "contributions": [ 242 | "doc" 243 | ] 244 | } 245 | ], 246 | "contributorsPerLine": 7, 247 | "projectName": "react", 248 | "projectOwner": "typescript-cheatsheets", 249 | "repoType": "github", 250 | "repoHost": "https://github.com", 251 | "skipCi": true, 252 | "commitType": "docs" 253 | } 254 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | */node_modules 2 | *.log 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/advanced-cheatsheet.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Advanced Cheatsheet 3 | about: Report Issue/Suggest an idea for Advanced Cheatsheet 4 | title: "[Advanced] ISSUE_TITLE_HERE" 5 | labels: ADVANCED 6 | assignees: "" 7 | --- 8 | 9 | **What cheatsheet is this about? (if applicable)** 10 | 11 | Advanced cheatsheet 12 | 13 | **What's your issue or idea?** 14 | 15 | _Write here_ 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/basic-cheatsheet.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Basic Cheatsheet 3 | about: Report Issue/Suggest an idea for Basic Cheatsheet 4 | title: "[Basic] ISSUE_TITLE_HERE" 5 | labels: BASIC 6 | assignees: sw-yx 7 | --- 8 | 9 | **What cheatsheet is this about? (if applicable)** 10 | 11 | Basic cheatsheet 12 | 13 | **What's your issue or idea?** 14 | 15 | _Write here_ 16 | 17 | **(If applicable) Reproduction of issue in TypeScript Playground** 18 | 19 | _[start with the basic TS + React template](https://www.typescriptlang.org/play/?jsx=2&esModuleInterop=true&q=222#example/typescript-with-react)_ 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/general-react-ts-question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: General React+TS Question 3 | about: Questions are welcome! We want to know and solve your pain points. 4 | title: "[Question] QUESTION_TITLE_HERE" 5 | labels: good first issue 6 | assignees: sw-yx 7 | --- 8 | 9 | **(If applicable) Reproduction of issue in TypeScript Playground** 10 | 11 | _[start with the basic TS + React template](https://www.typescriptlang.org/play/?jsx=2&esModuleInterop=true&q=222#example/typescript-with-react)_ 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/hoc-cheatsheet.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: HOC Cheatsheet 3 | about: Report Issue/Suggest an idea for HOC Cheatsheet 4 | title: "[HOC] ISSUE_TITLE_HERE" 5 | labels: HOC 6 | assignees: "" 7 | --- 8 | 9 | **What cheatsheet is this about? (if applicable)** 10 | 11 | HOC cheatsheet 12 | 13 | **What's your issue or idea?** 14 | 15 | _Write here_ 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/migrating-cheatsheet.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Migrating Cheatsheet 3 | about: Report Issue/Suggest an idea for Migrating Cheatsheet 4 | title: "[Migrating] ISSUE_TITLE_HERE" 5 | labels: MIGRATING 6 | assignees: "" 7 | --- 8 | 9 | **What cheatsheet is this about? (if applicable)** 10 | 11 | Migrating cheatsheet 12 | 13 | **What's your issue or idea?** 14 | 15 | _Write here_ 16 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | Thanks for contributing! 2 | 3 | - **If you are making a significant PR**, please make sure there is an open issue first 4 | - **If you're just fixing typos or adding small notes**, a brief explanation of why you'd like to add it would be nice :) 5 | 6 | **If you are contributing to README.md, DON'T**. README.md is auto-generated. Please just make edits to the source inside of `/docs/basic`. _Sorry, we get that it is a slight pain._ 7 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 60 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 7 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - pinned 8 | - security 9 | # Label to use when marking an issue as stale 10 | staleLabel: wontfix 11 | # Comment to post when marking an issue as stale. Set to `false` to disable 12 | markComment: > 13 | This issue has been automatically marked as stale because it has not had 14 | recent activity. It will be closed if no further activity occurs. Thank you 15 | for your contributions! 16 | # Comment to post when closing a stale issue. Set to `false` to disable 17 | closeComment: false 18 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: [main] 5 | pull_request: 6 | branches: [main] 7 | 8 | jobs: 9 | files-up-to-date: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout commit 13 | uses: actions/checkout@v4 14 | 15 | - name: Setup node 16 | uses: actions/setup-node@v4 17 | with: 18 | node-version-file: ".nvmrc" 19 | cache: yarn 20 | 21 | - name: Install dependencies 22 | run: yarn install --frozen-lockfile 23 | 24 | - name: "`yarn format` changes committed?" 25 | run: yarn format:check 26 | 27 | - name: "`yarn gen-readme` changes committed?" 28 | run: | 29 | yarn gen-readme 30 | git diff --exit-code 31 | -------------------------------------------------------------------------------- /.github/workflows/mlc_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "aliveStatusCodes": [200, 429] 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # Snowpack dependency directory (https://snowpack.dev/) 45 | web_modules/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | .parcel-cache 78 | 79 | # Next.js build output 80 | .next 81 | 82 | # Nuxt.js build / generate output 83 | .nuxt 84 | dist 85 | 86 | # Gatsby files 87 | .cache/ 88 | # Comment in the public line in if your project uses Gatsby and not Next.js 89 | # https://nextjs.org/blog/next-9-1#public-directory-support 90 | # public 91 | 92 | # vuepress build output 93 | .vuepress/dist 94 | 95 | # Serverless directories 96 | .serverless/ 97 | 98 | # FuseBox cache 99 | .fusebox/ 100 | 101 | # DynamoDB Local files 102 | .dynamodb/ 103 | 104 | # TernJS port file 105 | .tern-port 106 | 107 | # Stores VSCode versions used for testing VSCode extensions 108 | .vscode-test 109 | 110 | # Idea / Jetbrains IDE 111 | .idea 112 | 113 | # yarn v2 114 | .yarn/cache 115 | .yarn/unplugged 116 | .yarn/build-state.yml 117 | .pnp.* 118 | 119 | # Miscellaneous 120 | .history 121 | .DS_Store 122 | 123 | # Docusaurus files 124 | website/build 125 | website/.docusaurus 126 | website/.cache-loader 127 | 128 | # copy of contributors for the website 129 | website/src/pages/contributing.md 130 | website/src/pages/contributors.md 131 | 132 | # Local Netlify folder 133 | .netlify 134 | 135 | # Lock-files 136 | package-lock.json 137 | yarn.lock 138 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | yarn pretty-quick --staged 5 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 20.x 2 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Let's Contribute Together! 🚀 2 | 3 | We appreciate your interest in contributing to this project. Here are some core principles and a simplified project structure to make your contribution process more efficient and effective: 4 | 5 | ## 📋 Core Principles 6 | 7 | 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. 8 | 9 | 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. 10 | 11 | 3. **React + TypeScript Only**: We focus on React and TypeScript. React's ecosystem is vast, so we won't cover everything. If you think there's a need, consider maintaining separate lists for specialized topics, like React + Apollo GraphQL. We also don't aim to convince people to use TypeScript; we're here to assist those who have already chosen to use it. 12 | 13 | 4. **Add TypeScript Playground Links**: For code examples longer than four lines, include a link to the TypeScript Playground. Use the default TypeScript Playground options for the best experience. 14 | 15 | Your contributions will help countless developers, including your future self! 🙌 16 | 17 | ## 📁 Project Structure 18 | 19 | - **Content in `/docs`**: All the content resides here. 20 | - The content in `/docs/basic` is compiled into `README.md` to ensure that it's easy to read on GitHub. 21 | - **`/website` Folder**: This part consumes the content in `/docs`. It's a Docusaurus 2 site and includes Algolia search. A big thanks to both the Docusaurus and Algolia teams for their support! 22 | 23 | The website is deployed on Netlify, under swyx's personal account. 24 | 25 | To run the docsite locally, follow these steps: 26 | 27 | ```bash 28 | yarn # Install dependencies 29 | ## Ensure dependencies are also installed in /website 30 | cd website && yarn start 31 | ``` 32 | 33 | Here's an example of the expected output when the development server starts successfully: 34 | 35 | ``` 36 | yarn run v1.22.4 37 | warning package.json: No license field 38 | $ docusaurus start 39 | Starting the development server... 40 | 41 | ✔ Client 42 | Compiled successfully in 9.61s 43 | 44 | ℹ 「wds」: Project is running at http://localhost:3000/ 45 | ℹ 「wds」: webpack output is served from / 46 | ℹ 「wds」: Content not from webpack is served from /Users/wanshawn/Work/react-typescript-cheatsheet/website 47 | ℹ 「wds」: 404s will fallback to /index.html 48 | 49 | ✔ Client 50 | Compiled successfully in 116.41ms 51 | ``` 52 | 53 | Let's work together to enhance this resource and make it even more valuable to the developer community! 🌟👩‍💻👨‍💻 54 | -------------------------------------------------------------------------------- /CONTRIBUTORS.md: -------------------------------------------------------------------------------- 1 | ## Contributors 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 |
Ferdy Budhidharma
Ferdy Budhidharma

👀 🚧 🖋
swyx
swyx

🤔 👀 🚧 🖋 💬
Sebastian Silbermann
Sebastian Silbermann

👀 🚧 🖋
Islam Attrash
Islam Attrash

🚧 🖋
Stephen Koo
Stephen Koo

💬 💡
Andreas
Andreas

💻 📖 🚇
Arvind Srinivasan
Arvind Srinivasan

💻 🖋 📖 🚧
William R. J. Ribeiro
William R. J. Ribeiro

🤔
Alexandru-Dan Pop
Alexandru-Dan Pop

📖
Mathias Storm
Mathias Storm

📖
Sung M. Kim
Sung M. Kim

📖 🤔
Ryota Murakami
Ryota Murakami

💡 📖
Árpád Illyés
Árpád Illyés

💻
Igor Strebezhev
Igor Strebezhev

🤔 📖
David Johnston
David Johnston

📖
Kristóf Poduszló
Kristóf Poduszló

📖
james glasgow
james glasgow

📖
Ivan
Ivan

💻
Sebastian Andil
Sebastian Andil

📖
Adnan Husain
Adnan Husain

📖
martin
martin

📖
Filip Tammergård
Filip Tammergård

📖 💻
Joe Previte
Joe Previte

📖
Sasiru Ravihansa
Sasiru Ravihansa

📖
42 | 43 | 44 | 45 | 46 | 47 | 48 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): 49 | 50 | 51 | 52 | 53 | 54 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 55 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 shawn wang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /code-of-conduct.md: -------------------------------------------------------------------------------- 1 | # Our Code of Conduct 2 | 3 | This code of conduct outlines our expectations for participants within 4 | the [typescript-cheatsheets/react](https://github.com/typescript-cheatsheets/react) repository, as well as steps to 5 | reporting unacceptable behavior. We are committed to providing a welcoming and inspiring community for all and expect 6 | our code of conduct to be honored. Anyone who violates this code of conduct may be banned from the community. 7 | 8 | Our open source repository strives to: 9 | 10 | - **Be friendly and patient.** 11 | - **Be welcoming**: We strive to be a community that welcomes and supports people of all backgrounds and identities. 12 | This includes, but is not limited to members of any race, ethnicity, culture, national origin, colour, immigration 13 | status, social and economic class, educational level, sex, sexual orientation, gender identity and expression, age, 14 | size, family status, political belief, religion, and mental and physical ability. 15 | - **Be considerate**: Your work will be used by other people, and you in turn will depend on the work of others. Any 16 | decision you take will affect users and colleagues, and you should take those consequences into account when making 17 | decisions. Remember that we're a world-wide community, so you might not be communicating in someone else's primary 18 | language. 19 | - **Be respectful**: Not all of us will agree all the time, but disagreement is no excuse for poor behavior and poor 20 | manners. We might all experience some frustration now and then, but we cannot allow that frustration to turn into a 21 | personal attack. It’s important to remember that a community where people feel uncomfortable or threatened is not a 22 | productive one. 23 | - **Be careful in the words that you choose**: we are a community of professionals, and we conduct ourselves 24 | professionally. Be kind to others. Do not insult or put down other participants. Harassment and other exclusionary 25 | behavior aren't acceptable. This includes, but is not limited to: 26 | - Violent threats or language directed against another person. 27 | - Discriminatory jokes and language. 28 | - Posting sexually explicit or violent material. 29 | - Posting (or threatening to post) other people's personally identifying information ("doxing"). 30 | - Personal insults, especially those using racist or sexist terms. 31 | - Unwelcome sexual attention. 32 | - Advocating for, or encouraging, any of the above behavior. 33 | - Repeated harassment of others. In general, if someone asks you to stop, then stop. 34 | - **When we disagree, try to understand why**: Disagreements, both social and technical, happen all the time. It is 35 | important that we resolve disagreements and differing views constructively. Remember that we’re different. The 36 | strength of our community comes from its diversity, people from a wide range of backgrounds. Different people have 37 | different perspectives on issues. Being unable to understand why someone holds a viewpoint doesn’t mean that they’re 38 | wrong. Don’t forget that it is human to err and blaming each other doesn’t get us anywhere. Instead, focus on helping 39 | to resolve issues and learning from mistakes. 40 | 41 | This code is not exhaustive or complete. It serves to distill our common understanding of a collaborative, shared 42 | environment, and goals. We expect it to be followed in spirit as much as in the letter. 43 | 44 | ### Diversity Statement 45 | 46 | We encourage everyone to participate and are committed to building a repository for all. Although we may not be able to 47 | satisfy everyone, we all agree that everyone is equal. Whenever a participant has made a mistake, we expect them to take 48 | responsibility for it. If someone has been harmed or offended, it is our responsibility to listen carefully and 49 | respectfully, and do our best to right the wrong. 50 | 51 | Although this list cannot be exhaustive, we explicitly honor diversity in age, gender, gender identity or expression, 52 | culture, ethnicity, language, national origin, political beliefs, profession, race, religion, sexual orientation, 53 | socioeconomic status, and technical ability. We will not tolerate discrimination based on any of the protected 54 | characteristics above, including participants with disabilities. 55 | 56 | ### Reporting Issues 57 | 58 | If you experience or witness unacceptable behavior—or have any other concerns—please report it by contacting us (This 59 | repo is maintained by [@swyx](https://twitter.com/swyx), [@eps1lon](https://twitter.com/sebsilbermann) 60 | and [@filiptammergard](https://twitter.com/tammergard).). All reports will be handled with discretion. In your report 61 | please include: 62 | 63 | - Your contact information. 64 | - Names (real, nicknames, or pseudonyms) of any individuals involved. If there are additional witnesses, please include 65 | them as well. Your account of what occurred, and if you believe the incident is ongoing. If there is a publicly 66 | available record (e.g. a mailing list archive or a public IRC logger), please include a link. 67 | - Any additional information that may be helpful. 68 | 69 | After filing a report, a representative will contact you personally. If the person who is harassing you is part of the 70 | response team, they will recuse themselves from handling your incident. A representative will then review the incident, 71 | follow up with any additional questions, and make a decision as to how to respond. We will respect confidentiality 72 | requests for the purpose of protecting victims of abuse. 73 | 74 | Anyone asked to stop unacceptable behavior is expected to comply immediately. If an individual engages in unacceptable 75 | behavior, the representative may take any action they deem appropriate, up to and including a permanent ban from our 76 | community without warning. 77 | 78 | ## Version 79 | 80 | This is version 1.0.0 81 | 82 | ## Thanks 83 | 84 | This code of conduct is based on the [Open Code of Conduct](https://github.com/todogroup/opencodeofconduct) from 85 | the [TODOGroup](http://todogroup.org). 86 | 87 | We are thankful for their work and all the communities who have paved the way with code of conducts. 88 | -------------------------------------------------------------------------------- /copyFile.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const filesTopCopy = [ 3 | { 4 | src: "../CONTRIBUTORS.md", 5 | dest: "src/pages/contributors.md", 6 | }, 7 | { 8 | src: "../CONTRIBUTING.md", 9 | dest: "src/pages/contributing.md", 10 | }, 11 | ]; 12 | 13 | function copyFile(src, dest) { 14 | fs.copyFile(src, dest, (err) => { 15 | if (err) { 16 | console.log("Error Found:", err); 17 | } else { 18 | console.log("Files copied"); 19 | } 20 | }); 21 | } 22 | 23 | filesTopCopy.forEach(({ src, dest }) => { 24 | copyFile(src, dest); 25 | }); 26 | -------------------------------------------------------------------------------- /docs/advanced/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: intro 3 | sidebar_label: Intro 4 | title: Advanced Cheatsheet 5 | --- 6 | 7 | **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**. 8 | 9 | - It also has miscellaneous tips and tricks for pro users. 10 | - Advice for contributing to DefinitelyTyped 11 | - The goal is to take _full advantage_ of TypeScript. 12 | 13 | **Creating React + TypeScript Libraries** 14 | 15 | 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. 16 | 17 | 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. 18 | 19 | - Be sure to also check [`basarat`'s guide](https://basarat.gitbooks.io/typescript/content/docs/quick/library.html) for library tsconfig settings. 20 | - Alec Larson: [The best Rollup config for TypeScript libraries](https://gist.github.com/aleclarson/9900ed2a9a3119d865286b218e14d226) 21 | - From the Angular world, check out https://github.com/bitjson/typescript-starter 22 | -------------------------------------------------------------------------------- /docs/advanced/misc-concerns.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: misc_concerns 3 | title: "Section 3: Misc. Concerns" 4 | sidebar_label: Misc. Concerns 5 | --- 6 | 7 | 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. 8 | 9 | ## Writing TypeScript Libraries instead of Apps 10 | 11 | `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. 12 | 13 | ```ts 14 | interface MyComponentProps { 15 | autoHeight: boolean; 16 | secondProp: number; 17 | } 18 | 19 | export class MyComponent extends React.Component { 20 | static propTypes = { 21 | autoHeight: PropTypes.bool, 22 | secondProp: PropTypes.number.isRequired, 23 | }; 24 | } 25 | ``` 26 | 27 | [Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new). 28 | 29 | ## Commenting Components 30 | 31 | 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 (like the [Docz PropsTable](https://www.docz.site/docs/components-api#propstable)). The main thing to remember is to use `/** YOUR_COMMENT_HERE */` syntax in the line just above whatever you're annotating. 32 | 33 | ```tsx 34 | interface MyComponentProps { 35 | /** Description of prop "label". 36 | * @default foobar 37 | * */ 38 | label?: string; 39 | } 40 | 41 | /** 42 | * General component description in JSDoc format. Markdown is *supported*. 43 | */ 44 | export default function MyComponent({ label = "foobar" }: MyComponentProps) { 45 | return
Hello world {label}
; 46 | } 47 | ``` 48 | 49 | [View in the TypeScript Playground](https://www.typescriptlang.org/play/?jsx=2#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wFgAoC4AOxiSk3STgFkBPABRzAGc4BvCnDgB6AFRi4AESQ80UYGBjAI1OBExww3OACIANigBGSfboB0Q4ZIACAEySMArvqwQIRlFCtxJYkVaGJvoA-ABccDwwCtQA5gDcFAC+FBTiYkKSAOJI1PQo+nBouJB5tHAOcgpKKmo0cABSAMpSEGhwmNAgKDDmrF4A1nYQAO51fGI8TmCQsEh2YpbkvgHkSAAes-AOzq4dTtQYtaxsAMIlqrkwABT8cEGmcAC8ep0eXrpwSRHsXBC8AEoBFYiDAnFA1AAeOzAABuAD4ABKmfQQOAjaD6OwCB76JKQkQwhGJchJIA) 50 | 51 | [Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new). 52 | 53 | ## Namespaced Components 54 | 55 | 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()`; 56 | 57 | ```tsx 58 | import { forwardRef } from "react"; 59 | 60 | const Input = (props: any) => ; 61 | 62 | const Form = forwardRef( 63 | ({ children, ...otherProps }, ref) => ( 64 |
65 | {children} 66 |
67 | ) 68 | ); 69 | 70 | /** 71 | * Exported components now can be used as `
` and `` 72 | */ 73 | export default Object.assign(Form, { Input: Input }); 74 | ``` 75 | 76 | [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) 77 | 78 | (Contributed by @bryceosterhaus, see [further discussion](https://github.com/typescript-cheatsheets/react/issues/165)) 79 | 80 | [Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new). 81 | 82 | ## Design System Development 83 | 84 | 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) 85 | 86 | For developing with Storybook, read the docs I wrote over here: . This includes automatic proptype documentation generation, which is awesome :) 87 | 88 | [Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new). 89 | 90 | ## Migrating From Flow 91 | 92 | You should check out large projects that are migrating from flow to pick up concerns and tips: 93 | 94 | - [Jest](https://github.com/facebook/jest/pull/7554) 95 | - [Expo](https://github.com/expo/expo/issues/2164) 96 | - [React-beautiful-dnd](https://github.com/atlassian/react-beautiful-dnd/issues/982) 97 | - [Storybook](https://github.com/storybooks/storybook/issues/5030) 98 | - [VueJS](https://medium.com/the-vue-point/plans-for-the-next-iteration-of-vue-js-777ffea6fabf) 99 | 100 | Useful libraries: 101 | 102 | - 103 | - 104 | - 105 | 106 | If you have specific advice in this area, please file a PR! 107 | 108 | [Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new). 109 | 110 | ## Prettier 111 | 112 | There isn't any real secret to Prettier for TypeScript. But its a great idea to run prettier on every commit! 113 | 114 | ```bash 115 | $ yarn add -D prettier husky lint-staged 116 | ``` 117 | 118 | ```json 119 | // inside package.json 120 | { 121 | //... 122 | "husky": { 123 | "hooks": { 124 | "pre-commit": "lint-staged" 125 | } 126 | }, 127 | "lint-staged": { 128 | "linters": { 129 | "src/*.{ts,tsx,js,jsx,css,scss,md}": [ 130 | "prettier --trailing-comma es5 --single-quote --write", 131 | "git add" 132 | ], 133 | "ignore": ["**/dist/*, **/node_modules/*"] 134 | } 135 | }, 136 | "prettier": { 137 | "printWidth": 80, 138 | "semi": false, 139 | "singleQuote": true, 140 | "trailingComma": "es5" 141 | } 142 | } 143 | ``` 144 | 145 | 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) 146 | 147 | For library authors, this is set up for you in [tsdx](https://github.com/palmerhq/tsdx/pull/45/files). You may also wish to check out the newer https://ts-engine.dev/ project. 148 | 149 | ## Testing 150 | 151 | Yes, you can test your types! You shouldn't use it for EVERYTHING, but it can help prevent regressions: 152 | 153 | - https://github.com/azz/jest-runner-tsc 154 | - https://github.com/SamVerschueren/tsd 155 | - https://github.com/ikatyang/dts-jest ([Demo](https://codesandbox.io/s/dts-test-frozen-public-demo-iyorn)) 156 | - https://github.com/microsoft/dtslint ([Intro to dtslint](https://www.youtube.com/watch?v=nygcFEwOG8w&feature=share)) 157 | 158 | ## Working with Non-TypeScript Libraries (writing your own index.d.ts) 159 | 160 | Lets say you want to use `de-indent`, but it isn't typed or on DefinitelyTyped. You get an error like this: 161 | 162 | ``` 163 | [ts] 164 | 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. 165 | Try `npm install @types/de-indent` if it exists or add a new declaration (.d.ts) file containing `declare module 'de-indent';` [7016] 166 | ``` 167 | 168 | So create a `.d.ts` file anywhere in your project with the module definition: 169 | 170 | ```ts 171 | // de-indent.d.ts 172 | declare module "de-indent" { 173 | function deindent(): void; 174 | export = deindent; // default export 175 | } 176 | ``` 177 | 178 |
179 | 180 | Further Discussion 181 | 182 | 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). 183 | 184 |
185 | 186 | ## Compilation Speed 187 | 188 | Compiling large TS projects can get slow. Here are some tips: 189 | 190 | - We have a dedicated repo tracking TS speed recommendations: https://github.com/typescript-cheatsheets/speed 191 | - Use [TS 3.0 Project references](https://react-typescript-cheatsheet.netlify.app/docs/advanced/patterns_by_version#typescript-30) 192 | - 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) 193 | - Webpack ([see CRA diff](https://gist.github.com/jaredpalmer/d3016701589f14df8a3572df91a5754b)): 194 | - set `output.pathinfo = false` 195 | - set `optimization.splitChunks`, `optimization.removeAvailableModules`, `optimization.removeEmptyChunks` to `false` 196 | -------------------------------------------------------------------------------- /docs/advanced/types-react-ap.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: types_react_api 3 | title: "Section 4: @types/react and @types/react-dom APIs" 4 | sidebar_label: "@types/react and @types/react-dom APIs" 5 | --- 6 | 7 | The `@types` typings export both "public" types meant for your use as well as "private" types that are for internal use. 8 | 9 | Check [SaltyCrane's React TypeScript Cheatsheet](https://github.com/saltycrane/typescript-cheatsheet) for a nice autogenerated complete reference. 10 | 11 | ## `@types/react` 12 | 13 | [Link to `.d.ts`](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts) 14 | 15 | **Namespace: React** 16 | 17 | Most Commonly Used Interfaces and Types 18 | 19 | - `ReactNode` - anything that is renderable _inside_ of JSX, this is NOT the same as what can be rendered by a component! 20 | - `Component` - base class of all class-based components 21 | - `PureComponent` - base class for all class-based optimized components 22 | - `FC`, `FunctionComponent` - a complete interface for function components, often used to type external components instead of typing your own 23 | - `CSSProperties` - used to type style objects 24 | - all events: used to type event handlers 25 | - all event handlers: used to type event handlers 26 | - all consts: `Children`, `Fragment`, ... are all public and reflect the React runtime namespace 27 | 28 | Not Commonly Used but Good to know 29 | 30 | - `Ref` - used to type `innerRef` 31 | - `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) 32 | - `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 33 | - `ComponentType` - used for higher order components where you don't specifically deal with the intrinsic components 34 | - `ReactPortal` - used if you specifically need to type a prop as a portal, otherwise it is part of `ReactNode` 35 | - `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 36 | - `JSXElementConstructor` - anything that TypeScript considers to be a valid thing that can go into the opening tag of a JSX expression 37 | - `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) 38 | - `ComponentPropsWithRef` - props of a component where if it is a class-based component it will replace the `ref` prop with its own instance type 39 | - `ComponentPropsWithoutRef` - props of a component without its `ref` prop 40 | - `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): 41 | 42 |
43 | 44 | List of specialized HTMLAttributes 45 | 46 | 47 | Note that there are about 50 of these, which means there are some HTML elements which are not covered. 48 | 49 | - `AnchorHTMLAttributes` 50 | - `AudioHTMLAttributes` 51 | - `AreaHTMLAttributes` 52 | - `BaseHTMLAttributes` 53 | - `BlockquoteHTMLAttributes` 54 | - `ButtonHTMLAttributes` 55 | - `CanvasHTMLAttributes` 56 | - `ColHTMLAttributes` 57 | - `ColgroupHTMLAttributes` 58 | - `DataHTMLAttributes` 59 | - `DetailsHTMLAttributes` 60 | - `DelHTMLAttributes` 61 | - `DialogHTMLAttributes` 62 | - `EmbedHTMLAttributes` 63 | - `FieldsetHTMLAttributes` 64 | - `FormHTMLAttributes` 65 | - `HtmlHTMLAttributes` 66 | - `IframeHTMLAttributes` 67 | - `ImgHTMLAttributes` 68 | - `InsHTMLAttributes` 69 | - `InputHTMLAttributes` 70 | - `KeygenHTMLAttributes` 71 | - `LabelHTMLAttributes` 72 | - `LiHTMLAttributes` 73 | - `LinkHTMLAttributes` 74 | - `MapHTMLAttributes` 75 | - `MenuHTMLAttributes` 76 | - `MediaHTMLAttributes` 77 | - `MetaHTMLAttributes` 78 | - `MeterHTMLAttributes` 79 | - `QuoteHTMLAttributes` 80 | - `ObjectHTMLAttributes` 81 | - `OlHTMLAttributes` 82 | - `OptgroupHTMLAttributes` 83 | - `OptionHTMLAttributes` 84 | - `OutputHTMLAttributes` 85 | - `ParamHTMLAttributes` 86 | - `ProgressHTMLAttributes` 87 | - `SlotHTMLAttributes` 88 | - `ScriptHTMLAttributes` 89 | - `SelectHTMLAttributes` 90 | - `SourceHTMLAttributes` 91 | - `StyleHTMLAttributes` 92 | - `TableHTMLAttributes` 93 | - `TextareaHTMLAttributes` 94 | - `TdHTMLAttributes` 95 | - `ThHTMLAttributes` 96 | - `TimeHTMLAttributes` 97 | - `TrackHTMLAttributes` 98 | - `VideoHTMLAttributes` 99 | - `WebViewHTMLAttributes` 100 | 101 |
102 | 103 | - all methods: `createElement`, `cloneElement`, ... are all public and reflect the React runtime API 104 | 105 | [@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`. 106 | 107 | **Namespace: JSX** 108 | 109 | - `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). 110 | - `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. 111 | - `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. 112 | 113 | Not commonly used but good to know 114 | 115 | - `IntrinsicAttributes` set of attributes that all `IntrinsicElements` support... basically just `key`. 116 | - `ElementChildrenAttribute` name of property that TS looks at to figure out what types of children a component supports. Basically the `children` property 117 | - `ElementAttributesProperty` name of property that TS looks at to figure out what attributes a component supports. Basically the `props` property (for a class instance) 118 | 119 | **Don't use/Internal/Deprecated** 120 | 121 | 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. 122 | 123 | - `SFCElement` 124 | - `SFC` 125 | - `ComponentState` 126 | - `LegacyRef` 127 | - `StatelessComponent` 128 | - `ReactType` 129 | 130 | ### Adding non-standard attributes 131 | 132 | The attributes allowed on host components such as `button` or `img` follow the 133 | [HTML living standard](https://html.spec.whatwg.org/). New features that are not yet part of the living standard 134 | or are only implemented by certain browsers will therefore cause a type error. If 135 | you specifically write code for these browsers or polyfill these attributes you can 136 | use [module augmentation](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation) to still get those components type checked without having 137 | to use `any` or `@ts-ignore`. 138 | 139 | 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: 140 | 141 | ```ts 142 | // react-unstable-attributes.d.ts 143 | import "react"; 144 | 145 | declare module "react" { 146 | interface ImgHTMLAttributes extends HTMLAttributes { 147 | loading?: "auto" | "eager" | "lazy"; 148 | } 149 | } 150 | ``` 151 | 152 | ## `@types/react-dom` 153 | 154 | To be written 155 | -------------------------------------------------------------------------------- /docs/advanced/utility-types.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: utility_types 3 | title: "Utility Types" 4 | sidebar_label: Utility Types 5 | --- 6 | 7 | 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. 8 | 9 | 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. 10 | 11 | I also recommend having a good working knowledge of how to construct the inbuilt utility types from scratch. See [Dr. Rauschmayer's guide](https://2ality.com/2020/06/computing-with-types.html) for a concise introduction. 12 | 13 | A level of comfort with **generic types** is therefore required. Here are some helpful resources: 14 | 15 | - https://ts.chibicode.com/generics/ 16 | -------------------------------------------------------------------------------- /docs/basic/editor-integration.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: editor_integration 3 | title: Editor Tooling and Integration 4 | --- 5 | 6 | - VSCode 7 | - swyx's VSCode Extension: https://github.com/sw-yx/swyx-react-typescript-snippets 8 | - amVim: https://marketplace.visualstudio.com/items?itemName=auiworks.amvim 9 | - VIM 10 | - https://github.com/Quramy/tsuquyomi 11 | - nvim-typescript? 12 | - https://github.com/leafgarland/typescript-vim 13 | - peitalin/vim-jsx-typescript 14 | - NeoVim: https://github.com/neoclide/coc.nvim 15 | - other discussion: https://mobile.twitter.com/ryanflorence/status/1085715595994095620 16 | 17 | You are free to use this repo's TSX logo if you wish: 18 | 19 | [![https://user-images.githubusercontent.com/6764957/53868378-2b51fc80-3fb3-11e9-9cee-0277efe8a927.png](https://user-images.githubusercontent.com/6764957/53868378-2b51fc80-3fb3-11e9-9cee-0277efe8a927.png)](https://user-images.githubusercontent.com/6764957/53868378-2b51fc80-3fb3-11e9-9cee-0277efe8a927.png) 20 | 21 | You may also wish to use alternative logos - [jsx-tsx-logos](https://github.com/Protectator/jsx-tsx-logos) 22 | 23 | ![https://github.com/Protectator/jsx-tsx-logos/raw/master/example.png](https://github.com/Protectator/jsx-tsx-logos/raw/master/example.png) 24 | -------------------------------------------------------------------------------- /docs/basic/examples.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: examples 3 | title: Example App 4 | sidebar_label: Examples 5 | --- 6 | 7 | - [Create React App TypeScript Todo Example 2021](https://github.com/laststance/create-react-app-typescript-todo-example-2021) 8 | - [Ben Awad's 14 hour Fullstack React/GraphQL/TypeScript Tutorial](https://www.youtube.com/watch?v=I6ypD7qv3Z8) 9 | - [Cypress Realworld App](https://github.com/cypress-io/cypress-realworld-app) 10 | -------------------------------------------------------------------------------- /docs/basic/getting-started/basic-type-examples.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: basic_type_example 3 | title: Typing Component Props 4 | --- 5 | 6 | This is intended as a basic orientation and reference for React developers familiarizing with TypeScript. 7 | 8 | ## Basic Prop Types Examples 9 | 10 | A list of TypeScript types you will likely use in a React+TypeScript app: 11 | 12 | ```tsx 13 | type AppProps = { 14 | message: string; 15 | count: number; 16 | disabled: boolean; 17 | /** array of a type! */ 18 | names: string[]; 19 | /** string literals to specify exact string values, with a union type to join them together */ 20 | status: "waiting" | "success"; 21 | /** an object with known properties (but could have more at runtime) */ 22 | obj: { 23 | id: string; 24 | title: string; 25 | }; 26 | /** array of objects! (common) */ 27 | objArr: { 28 | id: string; 29 | title: string; 30 | }[]; 31 | /** any non-primitive value - can't access any properties (NOT COMMON but useful as placeholder) */ 32 | obj2: object; 33 | /** an interface with no required properties - (NOT COMMON, except for things like `React.Component<{}, State>`) */ 34 | obj3: {}; 35 | /** a dict object with any number of properties of the same type */ 36 | dict1: { 37 | [key: string]: MyTypeHere; 38 | }; 39 | dict2: Record; // equivalent to dict1 40 | /** function that doesn't take or return anything (VERY COMMON) */ 41 | onClick: () => void; 42 | /** function with named prop (VERY COMMON) */ 43 | onChange: (id: number) => void; 44 | /** function type syntax that takes an event (VERY COMMON) */ 45 | onChange: (event: React.ChangeEvent) => void; 46 | /** alternative function type syntax that takes an event (VERY COMMON) */ 47 | onClick(event: React.MouseEvent): void; 48 | /** any function as long as you don't invoke it (not recommended) */ 49 | onSomething: Function; 50 | /** an optional prop (VERY COMMON!) */ 51 | optional?: OptionalType; 52 | /** when passing down the state setter function returned by `useState` to a child component. `number` is an example, swap out with whatever the type of your state */ 53 | setState: React.Dispatch>; 54 | }; 55 | ``` 56 | 57 | ### `object` as the non-primitive type 58 | 59 | `object` is a common source of misunderstanding in TypeScript. It does not mean "any object" but rather "any non-primitive type", which means it represents anything that is not `number`, `bigint`, `string`, `boolean`, `symbol`, `null` or `undefined`. 60 | 61 | Typing "any non-primitive value" is most likely not something that you should do much in React, which means you will probably not use `object` much. 62 | 63 | ### Empty interface, `{}` and `Object` 64 | 65 | An empty interface, `{}` and `Object` all represent "any non-nullish value"—not "an empty object" as you might think. [Using these types is a common source of misunderstanding and is not recommended](https://typescript-eslint.io/rules/no-empty-interface/). 66 | 67 | ```ts 68 | interface AnyNonNullishValue {} // equivalent to `type AnyNonNullishValue = {}` or `type AnyNonNullishValue = Object` 69 | 70 | let value: AnyNonNullishValue; 71 | 72 | // these are all fine, but might not be expected 73 | value = 1; 74 | value = "foo"; 75 | value = () => alert("foo"); 76 | value = {}; 77 | value = { foo: "bar" }; 78 | 79 | // these are errors 80 | value = undefined; 81 | value = null; 82 | ``` 83 | 84 | ## Useful React Prop Type Examples 85 | 86 | Relevant for components that accept other React components as props. 87 | 88 | ```tsx 89 | export declare interface AppProps { 90 | children?: React.ReactNode; // best, accepts everything React can render 91 | childrenElement: React.JSX.Element; // A single React element 92 | style?: React.CSSProperties; // to pass through style props 93 | onChange?: React.FormEventHandler; // form events! the generic parameter is the type of event.target 94 | // more info: https://react-typescript-cheatsheet.netlify.app/docs/advanced/patterns_by_usecase/#wrappingmirroring 95 | props: Props & React.ComponentPropsWithoutRef<"button">; // to impersonate all the props of a button element and explicitly not forwarding its ref 96 | props2: Props & React.ComponentPropsWithRef; // to impersonate all the props of MyButtonForwardedRef and explicitly forwarding its ref 97 | } 98 | ``` 99 | 100 |
101 | Small React.ReactNode edge case before React 18 102 | 103 | Before the [React 18 type updates](https://github.com/DefinitelyTyped/DefinitelyTyped/pull/56210), this code typechecked but had a runtime error: 104 | 105 | ```tsx 106 | type Props = { 107 | children?: React.ReactNode; 108 | }; 109 | 110 | function Comp({ children }: Props) { 111 | return
{children}
; 112 | } 113 | function App() { 114 | // Before React 18: Runtime error "Objects are not valid as a React child" 115 | // After React 18: Typecheck error "Type '{}' is not assignable to type 'ReactNode'" 116 | return {{}}; 117 | } 118 | ``` 119 | 120 | This is because `ReactNode` includes `ReactFragment` which allowed type `{}` before React 18. 121 | 122 | [Thanks @pomle for raising this.](https://github.com/typescript-cheatsheets/react/issues/357) 123 | 124 |
125 | 126 |
127 | React.JSX.Element vs React.ReactNode? 128 | 129 | Quote [@ferdaber](https://github.com/typescript-cheatsheets/react/issues/57): A more technical explanation is that a valid React node is not the same thing as what is returned by `React.createElement`. Regardless of what a component ends up rendering, `React.createElement` always returns an object, which is the `React.JSX.Element` interface, but `React.ReactNode` is the set of all possible return values of a component. 130 | 131 | - `React.JSX.Element` -> Return value of `React.createElement` 132 | - `React.ReactNode` -> Return value of a component 133 | 134 |
135 | 136 | [More discussion: Where ReactNode does not overlap with React.JSX.Element](https://github.com/typescript-cheatsheets/react/issues/129) 137 | 138 | [Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new). 139 | 140 | ## Types or Interfaces? 141 | 142 | You can use either Types or Interfaces to type Props and State, so naturally the question arises - which do you use? 143 | 144 | ### TL;DR 145 | 146 | Use Interface until You Need Type - [orta](https://twitter.com/orta/status/1356129195835973632?s=20). 147 | 148 | ### More Advice 149 | 150 | Here's a helpful rule of thumb: 151 | 152 | - always use `interface` for public API's definition when authoring a library or 3rd party ambient type definitions, as this allows a consumer to extend them via _declaration merging_ if some definitions are missing. 153 | 154 | - consider using `type` for your React Component Props and State, for consistency and because it is more constrained. 155 | 156 | You can read more about the reasoning behind this rule of thumb in [Interface vs Type alias in TypeScript 2.7](https://medium.com/@martin_hotell/interface-vs-type-alias-in-typescript-2-7-2a8f1777af4c). 157 | 158 | The TypeScript Handbook now also includes guidance on [Differences Between Type Aliases and Interfaces](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#differences-between-type-aliases-and-interfaces). 159 | 160 | > Note: At scale, there are performance reasons to prefer interfaces ([see official Microsoft notes on this](https://github.com/microsoft/TypeScript/wiki/Performance#preferring-interfaces-over-intersections)) but [take this with a grain of salt](https://news.ycombinator.com/item?id=25201887) 161 | 162 | Types are useful for union types (e.g. `type MyType = TypeA | TypeB`) whereas Interfaces are better for declaring dictionary shapes and then `implementing` or `extending` them. 163 | 164 | ### Useful table for Types vs Interfaces 165 | 166 | It's a nuanced topic, don't get too hung up on it. Here's a handy table: 167 | 168 | | Aspect | Type | Interface | 169 | | ----------------------------------------------- | :--: | :-------: | 170 | | Can describe functions | ✅ | ✅ | 171 | | Can describe constructors | ✅ | ✅ | 172 | | Can describe tuples | ✅ | ✅ | 173 | | Interfaces can extend it | ⚠️ | ✅ | 174 | | Classes can extend it | 🚫 | ✅ | 175 | | Classes can implement it (`implements`) | ⚠️ | ✅ | 176 | | Can intersect another one of its kind | ✅ | ⚠️ | 177 | | Can create a union with another one of its kind | ✅ | 🚫 | 178 | | Can be used to create mapped types | ✅ | 🚫 | 179 | | Can be mapped over with mapped types | ✅ | ✅ | 180 | | Expands in error messages and logs | ✅ | 🚫 | 181 | | Can be augmented | 🚫 | ✅ | 182 | | Can be recursive | ⚠️ | ✅ | 183 | 184 | ⚠️ In some cases 185 | 186 | (source: [Karol Majewski](https://twitter.com/karoljmajewski/status/1082413696075382785)) 187 | 188 | [Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new). 189 | -------------------------------------------------------------------------------- /docs/basic/getting-started/class-components.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: class_components 3 | title: Class Components 4 | --- 5 | 6 | Within TypeScript, `React.Component` is a generic type (aka `React.Component`), so you want to provide it with (optional) prop and state type parameters: 7 | 8 | ```tsx 9 | type MyProps = { 10 | // using `interface` is also ok 11 | message: string; 12 | }; 13 | type MyState = { 14 | count: number; // like this 15 | }; 16 | class App extends React.Component { 17 | state: MyState = { 18 | // optional second annotation for better type inference 19 | count: 0, 20 | }; 21 | render() { 22 | return ( 23 |
24 | {this.props.message} {this.state.count} 25 |
26 | ); 27 | } 28 | } 29 | ``` 30 | 31 | [View in the TypeScript Playground](https://www.typescriptlang.org/play/?jsx=2#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wFgAoCmATzCTgFlqAFHMAZzgF44BvCuHAD0QuAFd2wAHYBzOAANpMJFEzok8uME4oANuwhwIAawFwQSduxQykALjjsYUaTIDcFAL4fyNOo2oAZRgUZW4+MzQIMSkYBykxEAAjFTdhUV1gY3oYAAttLx80XRQrOABBMDA4JAAPZSkAE05kdBgAOgBhXEgpJFiAHiZWCA4AGgDg0KQAPgjyQSdphyYpsJ5+BcF0ozAYYAgpPUckKKa4FCkpCBD9w7hMaDgUmGUoOD96aUwVfrQkMyCKIxOJwAAMZm8ZiITRUAAoAJTzbZwIgwMRQKRwOGA7YDRrAABuM1xKN4eW07TAbHY7QsVhsSE8fAptKWynawNinlJcAGQgJxNxCJ8gh55E8QA) 32 | 33 | Don't forget that you can export/import/extend these types/interfaces for reuse. 34 | 35 |
36 | Why annotate state twice? 37 | 38 | It isn't strictly necessary to annotate the `state` class property, but it allows better type inference when accessing `this.state` and also initializing the state. 39 | 40 | This is because they work in two different ways, the 2nd generic type parameter will allow `this.setState()` to work correctly, because that method comes from the base class, but initializing `state` inside the component overrides the base implementation so you have to make sure that you tell the compiler that you're not actually doing anything different. 41 | 42 | [See commentary by @ferdaber here](https://github.com/typescript-cheatsheets/react/issues/57). 43 | 44 |
45 | 46 |
47 | No need for readonly 48 | 49 | You often see sample code include `readonly` to mark props and state immutable: 50 | 51 | ```tsx 52 | type MyProps = { 53 | readonly message: string; 54 | }; 55 | type MyState = { 56 | readonly count: number; 57 | }; 58 | ``` 59 | 60 | This is not necessary as `React.Component` already marks them as immutable. ([See PR and discussion!](https://github.com/DefinitelyTyped/DefinitelyTyped/pull/26813)) 61 | 62 |
63 | 64 | **Class Methods**: Do it like normal, but just remember any arguments for your functions also need to be typed: 65 | 66 | ```tsx 67 | class App extends React.Component<{ message: string }, { count: number }> { 68 | state = { count: 0 }; 69 | render() { 70 | return ( 71 |
this.increment(1)}> 72 | {this.props.message} {this.state.count} 73 |
74 | ); 75 | } 76 | increment = (amt: number) => { 77 | // like this 78 | this.setState((state) => ({ 79 | count: state.count + amt, 80 | })); 81 | }; 82 | } 83 | ``` 84 | 85 | [View in the TypeScript Playground](https://www.typescriptlang.org/play/?jsx=2#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wFgAoCtAGxQGc64BBMMOJADxiQDsATRsnQwAdAGFckHrxgAeAN5wQSBigDmSAFxw6MKMB5q4AXwA0cRWggBXHjG09rIAEZIoJgHwWKcHTBTccAC8FnBWtvZwAAwmANw+cET8bgAUAJTe5L6+RDDWUDxwKQnZcLJ8wABucBA8YtTAaADWQfLpwV4wABbAdCIGaETKdikAjGnGHiWlFt29ImA4YH3KqhrGsz19ugFIIuF2xtO+sgD0FZVTWdlp8ddH1wNDMsFFKCCRji5uGUFe8tNTqc4A0mkg4HM6NNISI6EgYABlfzcFI7QJ-IoA66lA6RNF7XFwADUcHeMGmxjStwSxjuxiAA) 86 | 87 | **Class Properties**: If you need to declare class properties for later use, just declare it like `state`, but without assignment: 88 | 89 | ```tsx 90 | class App extends React.Component<{ 91 | message: string; 92 | }> { 93 | pointer: number; // like this 94 | componentDidMount() { 95 | this.pointer = 3; 96 | } 97 | render() { 98 | return ( 99 |
100 | {this.props.message} and {this.pointer} 101 |
102 | ); 103 | } 104 | } 105 | ``` 106 | 107 | [View in the TypeScript Playground](https://www.typescriptlang.org/play/?jsx=2#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wFgAoCtAGxQGc64BBMMOJADxiQDsATRsnQwAdAGFckHrxgAeAN4U4cEEgYoA5kgBccOjCjAeGgNwUAvgD44i8sshHuUXTwCuIAEZIoJuAHo-OGpgAGskOBgAC2A6JTg0SQhpHhgAEWA+AFkIVxSACgBKGzjlKJiRBxTvOABeOABmMzs4cziifm9C4ublIhhXKB44PJLlOFk+YAA3S1GxmzK6CpwwJdV1LXM4FH4F6KXKp1aesdk-SZnRgqblY-MgA) 108 | 109 | [Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new). 110 | 111 | ## Typing getDerivedStateFromProps 112 | 113 | 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. 114 | 115 | Here are a few ways in which you can annotate `getDerivedStateFromProps` 116 | 117 | 1. If you have explicitly typed your derived state and want to make sure that the return value from `getDerivedStateFromProps` conforms to it. 118 | 119 | ```tsx 120 | class Comp extends React.Component { 121 | static getDerivedStateFromProps( 122 | props: Props, 123 | state: State 124 | ): Partial | null { 125 | // 126 | } 127 | } 128 | ``` 129 | 130 | 2. When you want the function's return value to determine your state. 131 | 132 | ```tsx 133 | class Comp extends React.Component< 134 | Props, 135 | ReturnType 136 | > { 137 | static getDerivedStateFromProps(props: Props) {} 138 | } 139 | ``` 140 | 141 | 3. When you want derived state with other state fields and memoization 142 | 143 | ```tsx 144 | type CustomValue = any; 145 | interface Props { 146 | propA: CustomValue; 147 | } 148 | interface DefinedState { 149 | otherStateField: string; 150 | } 151 | type State = DefinedState & ReturnType; 152 | function transformPropsToState(props: Props) { 153 | return { 154 | savedPropA: props.propA, // save for memoization 155 | derivedState: props.propA, 156 | }; 157 | } 158 | class Comp extends React.PureComponent { 159 | constructor(props: Props) { 160 | super(props); 161 | this.state = { 162 | otherStateField: "123", 163 | ...transformPropsToState(props), 164 | }; 165 | } 166 | static getDerivedStateFromProps(props: Props, state: State) { 167 | if (isEqual(props.propA, state.savedPropA)) return null; 168 | return transformPropsToState(props); 169 | } 170 | } 171 | ``` 172 | 173 | [View in the TypeScript Playground](https://www.typescriptlang.org/play/?jsx=2#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wFgAoUSWOYAZwFEBHAVxQBs5tcD2IATFHQAWAOnpJWHMuQowAnmCRwAwizoxcANQ4tlAXjgoAdvIDcFYMZhIomdMoAKOMHTgBvCnDhgXAQQAuVXVNEB12PQtyAF9La1t7NGUAESRMKyR+AGUYFBsPLzgIGGFbHLykADFgJHZ+II0oKwBzKNjyBSU4cvzDVPTjTJ7lADJEJBgWKGMAFUUkAB5OpAhMOBgoEzpMaBBnCFcZiGGAPijMFmMMYAhjdc3jbd39w+PcmwAKXwO6IJe6ACUBXI3iIk2mwO83joKAAbpkXoEfC46KJvmA-AAaOAAehxcBh8K40DgICQIAgwAAXnkbsZCt5+LZgPDsu8kEF0aj0X5CtE2hQ0OwhG4VLgwHAkAAPGzGfhuZDoGCiRxTJBi8C3JDWBb-bGnSFwNC3RosDDQL4ov4ooGeEFQugsJRQS0-AFRKHrYT0UQaCpwQx2z3eYqlKDDaq1epwABEAEYAEwAZhjmIZUNEmY2Wx2UD2KKOw1drgB6f5fMKfpgwDQcGaE1STVZEZw+Z+xd+cD1BPZQWGtvTwDWH3ozDY7A7aP82KrSF9cIR-gBQLBUzuxhY7HYHqhq4h2ceubbryLXPdFZiQA) 174 | -------------------------------------------------------------------------------- /docs/basic/getting-started/concurrent.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: concurrent 3 | title: Concurrent React/React Suspense 4 | --- 5 | 6 | _Not written yet._ watch for more on React Suspense and Time Slicing. 7 | 8 | [Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new). 9 | -------------------------------------------------------------------------------- /docs/basic/getting-started/context.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: context 3 | title: Context 4 | --- 5 | 6 | ## Basic example 7 | 8 | Here's a basic example of creating a context containing the active theme. 9 | 10 | ```tsx 11 | import { createContext } from "react"; 12 | 13 | type ThemeContextType = "light" | "dark"; 14 | 15 | const ThemeContext = createContext("light"); 16 | ``` 17 | 18 | Wrap the components that need the context with a context provider: 19 | 20 | ```tsx 21 | import { useState } from "react"; 22 | 23 | const App = () => { 24 | const [theme, setTheme] = useState("light"); 25 | 26 | return ( 27 | 28 | 29 | 30 | ); 31 | }; 32 | ``` 33 | 34 | Call `useContext` to read and subscribe to the context. 35 | 36 | ```tsx 37 | import { useContext } from "react"; 38 | 39 | const MyComponent = () => { 40 | const theme = useContext(ThemeContext); 41 | 42 | return

The current theme is {theme}.

; 43 | }; 44 | ``` 45 | 46 | ## Without default context value 47 | 48 | If you don't have any meaningful default value, specify `null`: 49 | 50 | ```tsx 51 | import { createContext } from "react"; 52 | 53 | interface CurrentUserContextType { 54 | username: string; 55 | } 56 | 57 | const CurrentUserContext = createContext(null); 58 | ``` 59 | 60 | ```tsx 61 | const App = () => { 62 | const [currentUser, setCurrentUser] = useState({ 63 | username: "filiptammergard", 64 | }); 65 | 66 | return ( 67 | 68 | 69 | 70 | ); 71 | }; 72 | ``` 73 | 74 | Now that the type of the context can be `null`, you'll notice that you'll get a `'currentUser' is possibly 'null'` TypeScript error if you try to access the `username` property. You can use optional chaining to access `username`: 75 | 76 | ```tsx 77 | import { useContext } from "react"; 78 | 79 | const MyComponent = () => { 80 | const currentUser = useContext(CurrentUserContext); 81 | 82 | return

Name: {currentUser?.username}.

; 83 | }; 84 | ``` 85 | 86 | However, it would be preferable to not have to check for `null`, since we know that the context won't be `null`. One way to do that is to provide a custom hook to use the context, where an error is thrown if the context is not provided: 87 | 88 | ```tsx 89 | import { createContext } from "react"; 90 | 91 | interface CurrentUserContextType { 92 | username: string; 93 | } 94 | 95 | const CurrentUserContext = createContext(null); 96 | 97 | const useCurrentUser = () => { 98 | const currentUserContext = useContext(CurrentUserContext); 99 | 100 | if (!currentUserContext) { 101 | throw new Error( 102 | "useCurrentUser has to be used within " 103 | ); 104 | } 105 | 106 | return currentUserContext; 107 | }; 108 | ``` 109 | 110 | Using a runtime type check in this will has the benefit of printing a clear error message in the console when a provider is not wrapping the components properly. Now it's possible to access `currentUser.username` without checking for `null`: 111 | 112 | ```tsx 113 | import { useContext } from "react"; 114 | 115 | const MyComponent = () => { 116 | const currentUser = useCurrentUser(); 117 | 118 | return

Username: {currentUser.username}.

; 119 | }; 120 | ``` 121 | 122 | ### Type assertion as an alternative 123 | 124 | Another way to avoid having to check for `null` is to use type assertion to tell TypeScript you know the context is not `null`: 125 | 126 | ```tsx 127 | import { useContext } from "react"; 128 | 129 | const MyComponent = () => { 130 | const currentUser = useContext(CurrentUserContext); 131 | 132 | return

Name: {currentUser!.username}.

; 133 | }; 134 | ``` 135 | 136 | Another option is to use an empty object as default value and cast it to the expected context type: 137 | 138 | ```tsx 139 | const CurrentUserContext = createContext( 140 | {} as CurrentUserContextType 141 | ); 142 | ``` 143 | 144 | You can also use non-null assertion to get the same result: 145 | 146 | ```tsx 147 | const CurrentUserContext = createContext(null!); 148 | ``` 149 | 150 | When you don't know what to choose, prefer runtime checking and throwing over type asserting. 151 | -------------------------------------------------------------------------------- /docs/basic/getting-started/default-props.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: default_props 3 | title: Typing defaultProps 4 | --- 5 | 6 | ## You May Not Need `defaultProps` 7 | 8 | As per [this tweet](https://twitter.com/dan_abramov/status/1133878326358171650), defaultProps will eventually be deprecated. You can check the discussions here: 9 | 10 | - [Original tweet](https://twitter.com/hswolff/status/1133759319571345408) 11 | - More info can also be found in [this article](https://medium.com/@matanbobi/react-defaultprops-is-dying-whos-the-contender-443c19d9e7f1) 12 | 13 | The consensus is to use object default values. 14 | 15 | Function Components: 16 | 17 | ```tsx 18 | type GreetProps = { age?: number }; 19 | 20 | const Greet = ({ age = 21 }: GreetProps) => // etc 21 | ``` 22 | 23 | Class Components: 24 | 25 | ```tsx 26 | type GreetProps = { 27 | age?: number; 28 | }; 29 | 30 | class Greet extends React.Component { 31 | render() { 32 | const { age = 21 } = this.props; 33 | /*...*/ 34 | } 35 | } 36 | 37 | let el = ; 38 | ``` 39 | 40 | ## Typing `defaultProps` 41 | 42 | Type inference improved greatly for `defaultProps` in [TypeScript 3.0+](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-0.html), although [some edge cases are still problematic](https://github.com/typescript-cheatsheets/react/issues/61). 43 | 44 | **Function Components** 45 | 46 | ```tsx 47 | // using typeof as a shortcut; note that it hoists! 48 | // you can also declare the type of DefaultProps if you choose 49 | // e.g. https://github.com/typescript-cheatsheets/react/issues/415#issuecomment-841223219 50 | type GreetProps = { age: number } & typeof defaultProps; 51 | 52 | const defaultProps = { 53 | age: 21, 54 | }; 55 | 56 | const Greet = (props: GreetProps) => { 57 | // etc 58 | }; 59 | Greet.defaultProps = defaultProps; 60 | ``` 61 | 62 | _[See this in TS Playground](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAKjgQwM5wEoFNkGN4BmUEIcARFDvmQNwBQdMAnmFnAOKVYwAKxY6ALxwA3igDmWAFxwAdgFcQAIyxQ4AXzgAyOM1YQCcACZYCyeQBte-VPVwRZqeCbOXrEAXGEi6cCdLgAJgBGABo6dXo6e0d4TixuLzgACjAbGXjuPg9UAEovAD5RXzhKGHkoWTgAHiNgADcCkTScgDpkSTgAeiQFZVVELvVqrrrGiPpMmFaXcytsz2FZtwXbOiA)_ 63 | 64 | For **Class components**, there are [a couple ways to do it](https://github.com/typescript-cheatsheets/react/pull/103#issuecomment-481061483) (including using the `Pick` utility type) but the recommendation is to "reverse" the props definition: 65 | 66 | ```tsx 67 | type GreetProps = typeof Greet.defaultProps & { 68 | age: number; 69 | }; 70 | 71 | class Greet extends React.Component { 72 | static defaultProps = { 73 | age: 21, 74 | }; 75 | /*...*/ 76 | } 77 | 78 | // Type-checks! No type assertions needed! 79 | let el = ; 80 | ``` 81 | 82 |
83 | React.JSX.LibraryManagedAttributes nuance for library authors 84 | 85 | The above implementations work fine for App creators, but sometimes you want to be able to export `GreetProps` so that others can consume it. The problem here is that the way `GreetProps` is defined, `age` is a required prop when it isn't because of `defaultProps`. 86 | 87 | The insight to have here is that [`GreetProps` is the _internal_ contract for your component, not the _external_, consumer facing contract](https://github.com/typescript-cheatsheets/react/issues/66#issuecomment-453878710). You could create a separate type specifically for export, or you could make use of the `React.JSX.LibraryManagedAttributes` utility: 88 | 89 | ```tsx 90 | // internal contract, should not be exported out 91 | type GreetProps = { 92 | age: number; 93 | }; 94 | 95 | class Greet extends Component { 96 | static defaultProps = { age: 21 }; 97 | } 98 | 99 | // external contract 100 | export type ApparentGreetProps = React.JSX.LibraryManagedAttributes< 101 | typeof Greet, 102 | GreetProps 103 | >; 104 | ``` 105 | 106 | This will work properly, although hovering over`ApparentGreetProps`may be a little intimidating. You can reduce this boilerplate with the`ComponentProps` utility detailed below. 107 | 108 |
109 | 110 | ## Consuming Props of a Component with defaultProps 111 | 112 | A component with `defaultProps` may seem to have some required props that actually aren't. 113 | 114 | ### Problem Statement 115 | 116 | Here's what you want to do: 117 | 118 | ```tsx 119 | interface IProps { 120 | name: string; 121 | } 122 | const defaultProps = { 123 | age: 25, 124 | }; 125 | const GreetComponent = ({ name, age }: IProps & typeof defaultProps) => ( 126 |
{`Hello, my name is ${name}, ${age}`}
127 | ); 128 | GreetComponent.defaultProps = defaultProps; 129 | 130 | const TestComponent = (props: React.ComponentProps) => { 131 | return

; 132 | }; 133 | 134 | // Property 'age' is missing in type '{ name: string; }' but required in type '{ age: number; }' 135 | const el = ; 136 | ``` 137 | 138 | ### Solution 139 | 140 | Define a utility that applies `React.JSX.LibraryManagedAttributes`: 141 | 142 | ```tsx 143 | type ComponentProps = T extends 144 | | React.ComponentType 145 | | React.Component 146 | ? React.JSX.LibraryManagedAttributes 147 | : never; 148 | 149 | const TestComponent = (props: ComponentProps) => { 150 | return

; 151 | }; 152 | 153 | // No error 154 | const el = ; 155 | ``` 156 | 157 | [_See this in TS Playground_](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAKjgQwM5wEoFNkGN4BmUEIcARFDvmQNwBQdMAnmFnAMImQB2W3MABWJhUAHgAqAPjgBeOOLhYAHjD4ATdNjwwAdJ3ARe-cSyyjg3AlihwB0gD6Yqu-Tz4xzl67cl04cAH44ACkAZQANHQAZYAAjKGQoJgBZZG5kAHMsNQBBGBgoOIBXVTFxABofPzgALjheADdrejoLVSgCPDYASSEIETgAb2r0kCw61AKLDPoAXzpcQ0m4NSxOooAbQWF0OWH-TPG4ACYAVnK6WfpF7mWAcUosGFdDd1k4AApB+uQxysO4LM6r0dnAAGRwZisCAEFZrZCbbb9VAASlk0g+1VEamADUkgwABgAJLAbDYQSogJg-MZwYDoAAkg1GWFmlSZh1mBNmogA9Di8XQUfQHlgni8jLpVustn0BnJpQjZTsWrzeXANsh2gwbstxFhJhK3nIPmAdnUjfw5WIoVgYXBReKuK9+JI0TJpPs4JQYEUoNw4KIABYARjgvN8VwYargADkIIooMQoAslvBSe8JAbns7JTSsDIyAQIBAyOHJDQgA) 158 | 159 | ## Misc Discussions and Knowledge 160 | 161 |
162 | Why does React.FC break defaultProps? 163 | 164 | You can check the discussions here: 165 | 166 | - https://medium.com/@martin_hotell/10-typescript-pro-tips-patterns-with-or-without-react-5799488d6680 167 | - https://github.com/DefinitelyTyped/DefinitelyTyped/issues/30695 168 | - https://github.com/typescript-cheatsheets/react/issues/87 169 | 170 | This is just the current state and may be fixed in future. 171 | 172 |
173 | 174 |
175 | TypeScript 2.9 and earlier 176 | 177 | For TypeScript 2.9 and earlier, there's more than one way to do it, but this is the best advice we've yet seen: 178 | 179 | ```ts 180 | type Props = Required & { 181 | /* additional props here */ 182 | }; 183 | 184 | export class MyComponent extends React.Component { 185 | static defaultProps = { 186 | foo: "foo", 187 | }; 188 | } 189 | ``` 190 | 191 | Our former recommendation used the `Partial type` feature in TypeScript, which means that the current interface will fulfill a partial version on the wrapped interface. In that way we can extend defaultProps without any changes in the types! 192 | 193 | ```ts 194 | interface IMyComponentProps { 195 | firstProp?: string; 196 | secondProp: IPerson[]; 197 | } 198 | 199 | export class MyComponent extends React.Component { 200 | public static defaultProps: Partial = { 201 | firstProp: "default", 202 | }; 203 | } 204 | ``` 205 | 206 | The problem with this approach is it causes complex issues with the type inference working with `React.JSX.LibraryManagedAttributes`. Basically it causes the compiler to think that when creating a JSX expression with that component, that all of its props are optional. 207 | 208 | [See commentary by @ferdaber here](https://github.com/typescript-cheatsheets/react/issues/57) and [here](https://github.com/typescript-cheatsheets/react/issues/61). 209 | 210 |
211 | 212 | [Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new). 213 | -------------------------------------------------------------------------------- /docs/basic/getting-started/error-boundaries.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: error_boundaries 3 | title: Error Boundaries 4 | --- 5 | 6 | ### Option 1: Using react-error-boundary 7 | 8 | [React-error-boundary](https://github.com/bvaughn/react-error-boundary) - is a lightweight package ready to use for this scenario with TS support built-in. 9 | This approach also lets you avoid class components that are not that popular anymore. 10 | 11 | ### Option 2: Writing your custom error boundary component 12 | 13 | If you don't want to add a new npm package for this, you can also write your own `ErrorBoundary` component. 14 | 15 | ```jsx 16 | import React, { Component, ErrorInfo, ReactNode } from "react"; 17 | 18 | interface Props { 19 | children?: ReactNode; 20 | } 21 | 22 | interface State { 23 | hasError: boolean; 24 | } 25 | 26 | class ErrorBoundary extends Component { 27 | public state: State = { 28 | hasError: false 29 | }; 30 | 31 | public static getDerivedStateFromError(_: Error): State { 32 | // Update state so the next render will show the fallback UI. 33 | return { hasError: true }; 34 | } 35 | 36 | public componentDidCatch(error: Error, errorInfo: ErrorInfo) { 37 | console.error("Uncaught error:", error, errorInfo); 38 | } 39 | 40 | public render() { 41 | if (this.state.hasError) { 42 | return

Sorry.. there was an error

; 43 | } 44 | 45 | return this.props.children; 46 | } 47 | } 48 | 49 | export default ErrorBoundary; 50 | 51 | ``` 52 | 53 | [Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new). 54 | -------------------------------------------------------------------------------- /docs/basic/getting-started/forms-and-events.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: forms_and_events 3 | title: Forms and Events 4 | --- 5 | 6 | If performance is not an issue (and it usually isn't!), inlining handlers is easiest as you can just use [type inference and contextual typing](https://www.typescriptlang.org/docs/handbook/type-inference.html#contextual-typing): 7 | 8 | ```tsx 9 | const el = ( 10 |