From 58159d27f3cf2d80ecb57ad62fe3a25c79089af6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Tammerg=C3=A5rd?= Date: Fri, 15 May 2026 16:29:48 +0200 Subject: [PATCH] dump outdated content --- README.md | 988 +----------------- docs/advanced/misc-concerns.md | 2 +- docs/advanced/patterns_by_usecase.md | 2 +- docs/advanced/patterns_by_version.md | 570 ---------- docs/basic/editor-integration.md | 23 - docs/basic/examples.md | 9 - .../getting-started/basic-type-examples.md | 26 - .../getting-started/function-components.md | 49 - docs/basic/getting-started/hooks.md | 2 +- docs/basic/linting.md | 4 - docs/basic/recommended/codebases.md | 58 - docs/basic/recommended/resources.md | 36 - docs/basic/recommended/talks.md | 17 - docs/basic/troubleshooting/learn-ts.md | 20 - docs/basic/troubleshooting/non-ts-files.md | 32 - .../troubleshooting/official-typings-bugs.md | 66 -- docs/basic/troubleshooting/operators.md | 24 - docs/basic/troubleshooting/ts-config.md | 51 - docs/basic/troubleshooting/types.md | 557 ---------- docs/basic/troubleshooting/utilities.md | 30 - genReadme.mjs | 95 -- website/sidebars.json | 27 +- 22 files changed, 5 insertions(+), 2683 deletions(-) delete mode 100644 docs/advanced/patterns_by_version.md delete mode 100644 docs/basic/editor-integration.md delete mode 100644 docs/basic/examples.md delete mode 100644 docs/basic/recommended/codebases.md delete mode 100644 docs/basic/recommended/resources.md delete mode 100644 docs/basic/recommended/talks.md delete mode 100644 docs/basic/troubleshooting/learn-ts.md delete mode 100644 docs/basic/troubleshooting/non-ts-files.md delete mode 100644 docs/basic/troubleshooting/official-typings-bugs.md delete mode 100644 docs/basic/troubleshooting/operators.md delete mode 100644 docs/basic/troubleshooting/ts-config.md delete mode 100644 docs/basic/troubleshooting/types.md delete mode 100644 docs/basic/troubleshooting/utilities.md diff --git a/README.md b/README.md index b7c63aa02..919c8a179 100644 --- a/README.md +++ b/README.md @@ -106,37 +106,7 @@ 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) - - [Troubleshooting Handbook: Types](#troubleshooting-handbook-types) - - [Union Types and Type Guarding](#union-types-and-type-guarding) - - [Optional Types](#optional-types) - - [Enum Types](#enum-types) - - [Type Assertion](#type-assertion) - - [Simulating Nominal Types](#simulating-nominal-types) - - [Intersection Types](#intersection-types) - - [Union Types](#union-types) - - [Overloading Function Types](#overloading-function-types) - - [Using Inferred Types](#using-inferred-types) - - [Using Partial Types](#using-partial-types) - - [The Types I need weren't exported!](#the-types-i-need-werent-exported) - - [The Types I need don't exist!](#the-types-i-need-dont-exist) - - [Slapping `any` on everything](#slapping-any-on-everything) - - [Autogenerate types](#autogenerate-types) - - [Typing Exported Hooks](#typing-exported-hooks) - - [Typing Exported Components](#typing-exported-components) - - [Frequent Known Problems with TypeScript](#frequent-known-problems-with-typescript) - - [TypeScript doesn't narrow after an object element null check](#typescript-doesnt-narrow-after-an-object-element-null-check) - - [TypeScript doesn't let you restrict the type of children](#typescript-doesnt-let-you-restrict-the-type-of-children) - - [Troubleshooting Handbook: Operators](#troubleshooting-handbook-operators) - - [Troubleshooting Handbook: Utilities](#troubleshooting-handbook-utilities) - - [Troubleshooting Handbook: tsconfig.json](#troubleshooting-handbook-tsconfigjson) - - [Troubleshooting Handbook: Fixing bugs in official typings](#troubleshooting-handbook-fixing-bugs-in-official-typings) - - [Troubleshooting Handbook: Globals, Images and other non-TS files](#troubleshooting-handbook-globals-images-and-other-non-ts-files) - - [Editor Tooling and Integration](#editor-tooling-and-integration) - [Linting](#linting) - - [Other React + TypeScript resources](#other-react--typescript-resources) - - [Recommended React + TypeScript talks](#recommended-react--typescript-talks) - - [Time to Really Learn TypeScript](#time-to-really-learn-typescript) - - [Example App](#example-app) - [My question isn't answered here!](#my-question-isnt-answered-here) - [Contributors](#contributors) @@ -229,55 +199,6 @@ Some differences from the "normal function" version: - It provides typechecking and autocomplete for static properties like `displayName`, `propTypes`, and `defaultProps`. - Note that there are some known issues using `defaultProps` with `React.FunctionComponent`. See [this issue for details](https://github.com/typescript-cheatsheets/react/issues/87). We maintain a separate `defaultProps` section you can also look up. -- Before the [React 18 type updates](https://github.com/DefinitelyTyped/DefinitelyTyped/pull/56210), `React.FunctionComponent` provided an implicit definition of `children` (see below), which was heavily debated and is one of the reasons [`React.FC` was removed from the Create React App TypeScript template](https://github.com/facebook/create-react-app/pull/8177). - -```tsx -// before React 18 types -const Title: React.FunctionComponent<{ title: string }> = ({ - children, - title, -}) =>
{children}
; -``` - -
-(Deprecated)Using React.VoidFunctionComponent or React.VFC instead - -In [@types/react 16.9.48](https://github.com/DefinitelyTyped/DefinitelyTyped/pull/46643), the `React.VoidFunctionComponent` or `React.VFC` type was added for typing `children` explicitly. -However, please be aware that `React.VFC` and `React.VoidFunctionComponent` were deprecated in React 18 (https://github.com/DefinitelyTyped/DefinitelyTyped/pull/59882), so this interim solution is no longer necessary or recommended in React 18+. - -Please use regular function components or `React.FC` instead. - -```ts -type Props = { foo: string }; - -// OK now, in future, error -const FunctionComponent: React.FunctionComponent = ({ - foo, - children, -}: Props) => { - return ( -
- {foo} {children} -
- ); // OK -}; - -// Error now, in future, deprecated -const VoidFunctionComponent: React.VoidFunctionComponent = ({ - foo, - children, -}) => { - return ( -
- {foo} - {children} -
- ); -}; -``` - -
- - _In the future_, it may automatically mark props as `readonly`, though that's a moot point if the props object is destructured in the parameter list. In most cases it makes very little difference which syntax is used, but you may prefer the more explicit nature of `React.FunctionComponent`. @@ -302,7 +223,7 @@ const [state, setState] = useState(false); // `setState` only takes booleans ``` -See also the [Using Inferred Types](https://react-typescript-cheatsheet.netlify.app/docs/basic/troubleshooting/types/#using-inferred-types) section if you need to use a complex type that you've relied on inference for. +If you need to use a complex type that you've relied on inference for, you can use `typeof` to capture the inferred type. However, many hooks are initialized with null-ish default values, and you may wonder how to provide types. Explicitly declare the type, and use a union type: @@ -1173,32 +1094,6 @@ export declare interface AppProps { } ``` -
-Small React.ReactNode edge case before React 18 - -Before the [React 18 type updates](https://github.com/DefinitelyTyped/DefinitelyTyped/pull/56210), this code typechecked but had a runtime error: - -```tsx -type Props = { - children?: React.ReactNode; -}; - -function Comp({ children }: Props) { - return
{children}
; -} -function App() { - // Before React 18: Runtime error "Objects are not valid as a React child" - // After React 18: Typecheck error "Type '{}' is not assignable to type 'ReactNode'" - return {{}}; -} -``` - -This is because `ReactNode` includes `ReactFragment` which allowed type `{}` before React 18. - -[Thanks @pomle for raising this.](https://github.com/typescript-cheatsheets/react/issues/357) - -
-
React.JSX.Element vs React.ReactNode? @@ -2017,805 +1912,10 @@ _Not written yet._ watch [https://github.com/sw-yx/fresh-async-react](https://gi - - -### Troubleshooting Handbook: Types - -> ⚠️ Have you read [the TypeScript FAQ](https://github.com/microsoft/TypeScript/wiki/FAQ?) Your answer might be there! - -Facing weird type errors? You aren't alone. This is the hardest part of using TypeScript with React. Be patient - you are learning a new language after all. However, the more you get good at this, the less time you'll be working _against_ the compiler and the more the compiler will be working _for_ you! - -Try to avoid typing with `any` as much as possible to experience the full benefits of TypeScript. Instead, let's try to be familiar with some of the common strategies to solve these issues. - -#### Union Types and Type Guarding - -Union types are handy for solving some of these typing problems: - -```tsx -class App extends React.Component< - {}, - { - count: number | null; // like this - } -> { - state = { - count: null, - }; - render() { - return
this.increment(1)}>{this.state.count}
; - } - increment = (amt: number) => { - this.setState((state) => ({ - count: (state.count || 0) + amt, - })); - }; -} -``` - -[View in the TypeScript Playground](https://www.typescriptlang.org/play/?jsx=2#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wFgAoCtAGxQGc64BBMMOJADxiQDsATRsnQwAdAGFckHrxgAeCnDgBvAL4AaBcs2K0EAK48YALjg89IAEZIocAD6m91agG44AejdxqwANZI4MAAWwHSaKhQAfFrkinQwKNxwALzRijr6hiZmTmHOmkT81gAUAJSpaUQwelA8cLJ8wABucBA8Yt5oPklKpclRQSEiwDxoRCAyRQCMJSoRSgN0InEJSCK6BjAqsm4NjRF5MXDhh8OjSOOGyXBFKCDGDpbWZUlRStoBwYt0SDAAyvHcIrLRIva5vQ5pODrTLXYGraHwWz2AAMZQA1HBbjB3ioSiUDooVAcVEA) - -**Type Guarding**: Sometimes Union Types solve a problem in one area but create another downstream. If `A` and `B` are both object types, `A | B` means "either A or B" (not both at once - that would be an intersection type `A & B`). TypeScript will only let you access properties that exist on both types unless you use type guards to narrow the type. Learn how to write checks, guards, and assertions (also see the Conditional Rendering section below). For example: - -```ts -interface Admin { - role: string; -} -interface User { - email: string; -} - -// Method 1: use `in` keyword -function redirect(user: Admin | User) { - if ("role" in user) { - // use the `in` operator for typeguards since TS 2.7+ - routeToAdminPage(user.role); - } else { - routeToHomePage(user.email); - } -} - -// Method 2: custom type guard, does the same thing in older TS versions or where `in` isnt enough -function isAdmin(user: Admin | User): user is Admin { - return (user as any).role !== undefined; -} -``` - -[View in the TypeScript Playground](https://www.typescriptlang.org/play/?jsx=2#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wFgAoC4AOxiSk3STgEEATEGuAbwrjhwAbJAC44AZxhQaAcwDcFAL5Va9RmmYBVcfR584SECmCCxk6dXlKKFTAFdqGYBGoCIdugBUI7TtQAKKDJIABTiwDLUwJjA9ACUeuT80XBhEVExugC8OQR2OlAIEML4CbxJ-AJIMHZQrvi+NGQVinDWlOT2jjDOrjgeSN4AErhIgcFpkdGxUGX6KZMZM3A5WQSGxoKliZVVNXUEIyBIYEFIzfzK5FcUAPS3cACy1QAWEGxwAIxi+cwABjQ-nAANZIACeAHdoGxbA4nC4qmxgEQMCFflAxI1XAAfODaeI7ODREIAIiESBJRNc6LKcHucF+cBgL3+gLgEDA9BQMGgcEwvJgYM5MjsKCgbHEEhoGjgngAynAAEwAOgA7ABqfT8fpeHwcGjjULo5XkuIKFoGQQ6Qna9y6o5jM5ogrKjYmM36K43cj057M95KsRofI8vCCzlwEVitgAGjgbAgSElzOY4hQxyZL1kVPZgjYunlcAAbvRwi5JbyISyiHAAdQgcBxLQDNR3DIXrDur0ieIsc76Jj9Ti8QU4j8Cj3WEPCUR9q5+1A4ChJShqGC4ibiswAIS5Bz5mLUJAw65AA) - -Method 2 is also known as [User-Defined Type Guards](https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards) and can be really handy for readable code. This is how TS itself refines types with `typeof` and `instanceof`. - -If you need `if...else` chains or the `switch` statement instead, it should "just work", but look up [Discriminated Unions](https://www.typescriptlang.org/docs/handbook/advanced-types.html#discriminated-unions) if you need help. (See also: [Basarat's writeup](https://basarat.gitbook.io/typescript/type-system/discriminated-unions)). This is handy in typing reducers for `useReducer` or Redux. - -#### Optional Types - -If a component has an optional prop, add a question mark and assign during destructure (or use defaultProps). - -```tsx -class MyComponent extends React.Component<{ - message?: string; // like this -}> { - render() { - const { message = "default" } = this.props; - return
{message}
; - } -} -``` - -You can also use a `!` character to assert that something is not undefined, but this is not encouraged. - -_Something to add? [File an issue](https://github.com/typescript-cheatsheets/react/issues/new) with your suggestions!_ - -#### Enum Types - -**We recommend avoiding using enums as far as possible**. - -Enums have a few [documented issues](https://fettblog.eu/tidy-typescript-avoid-enums/) (the TS team [agrees](https://twitter.com/orta/status/1348966323271987201?s=20)). A simpler alternative to enums is just declaring a union type of string literals: - -```tsx -export declare type Position = "left" | "right" | "top" | "bottom"; -``` - -If you must use enums, remember that enums in TypeScript default to numbers. You will usually want to use them as strings instead: - -```tsx -export enum ButtonSizes { - default = "default", - small = "small", - large = "large", -} - -// usage -export const PrimaryButton = ( - props: Props & React.HTMLProps -) => ; -}; -``` - -_Playground [here](https://www.typescriptlang.org/play?ssl=4&ssc=1&pln=12&pc=2#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wFgAoCipAD0ljmADsYkpN0k4AFKUFKAE8AQgFcYMCE14QwAZzgBvCnDgAbFACMkagFxw5MPkwDmAbgoBfanWjw0Uwzz4gBI8ZKZwAvHAAUKnBgOPL6vPxCYhJSMvJwAGSIxDAAdFGeABIAKgCyADIAghJ8muJIcgA82fnpUgCiakggSCwAfBQAlD6tSoEA9H1wACYQcGiihrhwpdFMggYwopiYgUSLUF4VM55KKXvBsnKWPYoH8ika2mqWcBV921KtFuSWQA)_ - -You can also use Intersection Types to make reusable subsets of props for similar components: - -```tsx -type BaseProps = { - className?: string, - style?: React.CSSProperties - name: string // used in both -} -type DogProps = { - tailsCount: number -} -type HumanProps = { - handsCount: number -} -export const Human = (props: BaseProps & HumanProps) => // ... -export const Dog = (props: BaseProps & DogProps) => // ... -``` - -[View in the TypeScript Playground](https://www.typescriptlang.org/play/?jsx=2#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wFgAoCmATzCTgCEUBnJABRzGbgF44BvCnGFoANi2YA5FCCQB+AFxxmMKMAB2AcwA0Q4Suqj5S5OhgA6AMIBlaxwh1YwJMz1x1MpEpVqtcAPT+cACurAAmcBpwAEYQMAAWFAC+VLT0ACIQmvZcvAJ6MCjAosyWEMHqMErqwSDRSFDJqXRwABK1KOo53HyC5MLxnWGl5ZXVtfWN5CnkSAAekLBwaBDqKm0d6ibEFgBilgA8TKzdcABkGyCd3QB8eQAUAJS8d-d6B2HAAG4BNxSPFAo80W8BWa3gmU02zM5n2RxY7E43AukNuD2ePFe70+P38f3IjyAA) - -Make sure not to confuse Intersection Types (which are **and** operations) with Union Types (which are **or** operations). - -#### Union Types - -This section is yet to be written (please contribute!). Meanwhile, see our [commentary on Union Types usecases](https://github.com/typescript-cheatsheets/react/blob/main/README.md#union-types-and-type-guarding). - -The ADVANCED cheatsheet also has information on Discriminated Union Types, which are helpful when TypeScript doesn't seem to be narrowing your union type as you expect. - -#### Overloading Function Types - -Specifically when it comes to functions, you may need to overload instead of union type. The most common way function types are written uses the shorthand: - -```ts -type FunctionType1 = (x: string, y: number) => number; -``` - -But this doesn't let you do any overloading. If you have the implementation, you can put them after each other with the function keyword: - -```ts -function pickCard(x: { suit: string; card: number }[]): number; -function pickCard(x: number): { suit: string; card: number }; -function pickCard(x): any { - // implementation with combined signature - // ... -} -``` - -However, if you don't have an implementation and are just writing a `.d.ts` definition file, this won't help you either. In this case you can forego any shorthand and write them the old-school way. The key thing to remember here is as far as TypeScript is concerned, `functions are just callable objects with no key`: - -```ts -type pickCard = { - (x: { suit: string; card: number }[]): number; - (x: number): { suit: string; card: number }; - // no need for combined signature in this form - // you can also type static properties of functions here eg `pickCard.wasCalled` -}; -``` - -Note that when you implement the actual overloaded function, the implementation will need to declare the combined call signature that you'll be handling, it won't be inferred for you. You can readily see examples of overloads in DOM APIs, e.g. `createElement`. - -[Read more about Overloading in the Handbook.](https://www.typescriptlang.org/docs/handbook/functions.html#overloads) - -#### Using Inferred Types - -Leaning on TypeScript's Type Inference is great... until you realize you need a type that was inferred, and have to go back and explicitly declare types/interfaces so you can export them for reuse. - -Fortunately, with `typeof`, you won't have to do that. Just use it on any value: - -```tsx -const [state, setState] = useState({ - foo: 1, - bar: 2, -}); // state's type inferred to be {foo: number, bar: number} - -const someMethod = (obj: typeof state) => { - // grabbing the type of state even though it was inferred - // some code using obj - setState(obj); // this works -}; -``` - -#### Using Partial Types - -Working with slicing state and props is common in React. Again, you don't really have to go and explicitly redefine your types if you use the `Partial` generic type: - -```tsx -const [state, setState] = useState({ - foo: 1, - bar: 2, -}); // state's type inferred to be {foo: number, bar: number} - -// NOTE: stale state merging is not actually encouraged in useState -// we are just demonstrating how to use Partial here -const partialStateUpdate = (obj: Partial) => - setState({ ...state, ...obj }); - -// later on... -partialStateUpdate({ foo: 2 }); // this works -``` - -
-Minor caveats on using Partial - -Note that there are some TS users who don't agree with using `Partial` as it behaves today. See [subtle pitfalls of the above example here](https://twitter.com/ferdaber/status/1084798596027957248), and check out this long discussion on [why @types/react uses Pick instead of Partial](https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18365). - -
- -#### The Types I need weren't exported! - -This can be annoying but here are ways to grab the types! - -- Grabbing the Prop types of a component: Use `React.ComponentProps` and `typeof`, and optionally `Omit` any overlapping types - -```tsx -import { Button } from "library"; // but doesn't export ButtonProps! oh no! -type ButtonProps = React.ComponentProps; // no problem! grab your own! -type AlertButtonProps = Omit; // modify -const AlertButton = (props: AlertButtonProps) => ( - ; -}; -``` - -_Playground [here](https://www.typescriptlang.org/play?ssl=4&ssc=1&pln=12&pc=2#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wFgAoCipAD0ljmADsYkpN0k4AFKUFKAE8AQgFcYMCE14QwAZzgBvCnDgAbFACMkagFxw5MPkwDmAbgoBfanWjw0Uwzz4gBI8ZKZwAvHAAUKnBgOPL6vPxCYhJSMvJwAGSIxDAAdFGeABIAKgCyADIAghJ8muJIcgA82fnpUgCiakggSCwAfBQAlD6tSoEA9H1wACYQcGiihrhwpdFMggYwopiYgUSLUF4VM55KKXvBsnKWPYoH8ika2mqWcBV921KtFuSWQA)_ - -You can also use Intersection Types to make reusable subsets of props for similar components: - -```tsx -type BaseProps = { - className?: string, - style?: React.CSSProperties - name: string // used in both -} -type DogProps = { - tailsCount: number -} -type HumanProps = { - handsCount: number -} -export const Human = (props: BaseProps & HumanProps) => // ... -export const Dog = (props: BaseProps & DogProps) => // ... -``` - -[View in the TypeScript Playground](https://www.typescriptlang.org/play/?jsx=2#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wFgAoCmATzCTgCEUBnJABRzGbgF44BvCnGFoANi2YA5FCCQB+AFxxmMKMAB2AcwA0Q4Suqj5S5OhgA6AMIBlaxwh1YwJMz1x1MpEpVqtcAPT+cACurAAmcBpwAEYQMAAWFAC+VLT0ACIQmvZcvAJ6MCjAosyWEMHqMErqwSDRSFDJqXRwABK1KOo53HyC5MLxnWGl5ZXVtfWN5CnkSAAekLBwaBDqKm0d6ibEFgBilgA8TKzdcABkGyCd3QB8eQAUAJS8d-d6B2HAAG4BNxSPFAo80W8BWa3gmU02zM5n2RxY7E43AukNuD2ePFe70+P38f3IjyAA) - -Make sure not to confuse Intersection Types (which are **and** operations) with Union Types (which are **or** operations). - -## Union Types - -This section is yet to be written (please contribute!). Meanwhile, see our [commentary on Union Types usecases](https://github.com/typescript-cheatsheets/react/blob/main/README.md#union-types-and-type-guarding). - -The ADVANCED cheatsheet also has information on Discriminated Union Types, which are helpful when TypeScript doesn't seem to be narrowing your union type as you expect. - -## Overloading Function Types - -Specifically when it comes to functions, you may need to overload instead of union type. The most common way function types are written uses the shorthand: - -```ts -type FunctionType1 = (x: string, y: number) => number; -``` - -But this doesn't let you do any overloading. If you have the implementation, you can put them after each other with the function keyword: - -```ts -function pickCard(x: { suit: string; card: number }[]): number; -function pickCard(x: number): { suit: string; card: number }; -function pickCard(x): any { - // implementation with combined signature - // ... -} -``` - -However, if you don't have an implementation and are just writing a `.d.ts` definition file, this won't help you either. In this case you can forego any shorthand and write them the old-school way. The key thing to remember here is as far as TypeScript is concerned, `functions are just callable objects with no key`: - -```ts -type pickCard = { - (x: { suit: string; card: number }[]): number; - (x: number): { suit: string; card: number }; - // no need for combined signature in this form - // you can also type static properties of functions here eg `pickCard.wasCalled` -}; -``` - -Note that when you implement the actual overloaded function, the implementation will need to declare the combined call signature that you'll be handling, it won't be inferred for you. You can readily see examples of overloads in DOM APIs, e.g. `createElement`. - -[Read more about Overloading in the Handbook.](https://www.typescriptlang.org/docs/handbook/functions.html#overloads) - -## Using Inferred Types - -Leaning on TypeScript's Type Inference is great... until you realize you need a type that was inferred, and have to go back and explicitly declare types/interfaces so you can export them for reuse. - -Fortunately, with `typeof`, you won't have to do that. Just use it on any value: - -```tsx -const [state, setState] = useState({ - foo: 1, - bar: 2, -}); // state's type inferred to be {foo: number, bar: number} - -const someMethod = (obj: typeof state) => { - // grabbing the type of state even though it was inferred - // some code using obj - setState(obj); // this works -}; -``` - -## Using Partial Types - -Working with slicing state and props is common in React. Again, you don't really have to go and explicitly redefine your types if you use the `Partial` generic type: - -```tsx -const [state, setState] = useState({ - foo: 1, - bar: 2, -}); // state's type inferred to be {foo: number, bar: number} - -// NOTE: stale state merging is not actually encouraged in useState -// we are just demonstrating how to use Partial here -const partialStateUpdate = (obj: Partial) => - setState({ ...state, ...obj }); - -// later on... -partialStateUpdate({ foo: 2 }); // this works -``` - -
-Minor caveats on using Partial - -Note that there are some TS users who don't agree with using `Partial` as it behaves today. See [subtle pitfalls of the above example here](https://twitter.com/ferdaber/status/1084798596027957248), and check out this long discussion on [why @types/react uses Pick instead of Partial](https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18365). - -
- -## The Types I need weren't exported! - -This can be annoying but here are ways to grab the types! - -- Grabbing the Prop types of a component: Use `React.ComponentProps` and `typeof`, and optionally `Omit` any overlapping types - -```tsx -import { Button } from "library"; // but doesn't export ButtonProps! oh no! -type ButtonProps = React.ComponentProps; // no problem! grab your own! -type AlertButtonProps = Omit; // modify -const AlertButton = (props: AlertButtonProps) => ( -