From bb508e925294e44389a27c981425faa115cb3539 Mon Sep 17 00:00:00 2001 From: Orta Therox Date: Thu, 22 Jun 2023 21:05:51 +0100 Subject: [PATCH 01/24] Start of the typescript page --- src/components/Layout/Footer.tsx | 1 + src/content/learn/typescript.md | 56 ++++++++++++++++++++++++++++++++ src/sidebarLearn.json | 4 +++ 3 files changed, 61 insertions(+) create mode 100644 src/content/learn/typescript.md diff --git a/src/components/Layout/Footer.tsx b/src/components/Layout/Footer.tsx index 4d0b066461f..cd0cf25793c 100644 --- a/src/components/Layout/Footer.tsx +++ b/src/components/Layout/Footer.tsx @@ -290,6 +290,7 @@ export function Footer() { Quick Start Installation + Using TypeScript Describing the UI diff --git a/src/content/learn/typescript.md b/src/content/learn/typescript.md new file mode 100644 index 00000000000..4007ac61e0f --- /dev/null +++ b/src/content/learn/typescript.md @@ -0,0 +1,56 @@ +--- +title: Using TypeScript +--- + + + +TypeScript is a popular way to add type definitions to React projects. Out of the box, TypeScript [supports JSX](/learn/writing-markup-with-jsx) and you can get full React support by adding [`@types/react-dom`](https://www.npmjs.com/package/@types/react-dom) to your project. + + + + +* [How does ](/learn/start-a-new-react-project) +* [How to add React to an existing project](/learn/add-react-to-an-existing-project) +* [How to set up your editor](/learn/editor-setup) +* [How to install React Developer Tools](/learn/react-developer-tools) + + + +## Try React {/*try-react*/} + +You don't need to install anything to play with React. Try editing this sandbox! + + + +```tsx App.tsx active +function Greeting({ name } : { name: string }) { + return

Hello, {name}

; +} + +export default function App() { + return +} +``` + +
+ +You can edit it directly or open it in a new tab by pressing the "Fork" button in the upper right corner. + +Most pages in the React documentation contain sandboxes like this. Outside of the React documentation, there are many online sandboxes that support React: for example, [CodeSandbox](https://codesandbox.io/s/new), [StackBlitz](https://stackblitz.com/fork/react), or [CodePen.](https://codepen.io/pen?&editors=0010&layout=left&prefill_data_id=3f4569d1-1b11-4bce-bd46-89090eed5ddb) + +### Try React locally {/*try-react-locally*/} + +To try React locally on your computer, [download this HTML page.](https://gist.githubusercontent.com/gaearon/0275b1e1518599bbeafcde4722e79ed1/raw/db72dcbf3384ee1708c4a07d3be79860db04bff0/example.html) Open it in your editor and in your browser! + +## Start a new React project {/*start-a-new-react-project*/} + +If you want to build an app or a website fully with React, [start a new React project.](/learn/start-a-new-react-project) + +## Add React to an existing project {/*add-react-to-an-existing-project*/} + +If want to try using React in your existing app or a website, [add React to an existing project.](/learn/add-react-to-an-existing-project) + +## Next steps {/*next-steps*/} + +Head to the [Quick Start](/learn) guide for a tour of the most important React concepts you will encounter every day. + diff --git a/src/sidebarLearn.json b/src/sidebarLearn.json index 89d5cffca0c..f462c696e8c 100644 --- a/src/sidebarLearn.json +++ b/src/sidebarLearn.json @@ -36,6 +36,10 @@ "title": "Editor Setup", "path": "/learn/editor-setup" }, + { + "title": "Using TypeScript", + "path": "/learn/typescript" + }, { "title": "React Developer Tools", "path": "/learn/react-developer-tools" From c897491acc2c7faefbb5bb03e950f8b25ab7c20a Mon Sep 17 00:00:00 2001 From: orta Date: Tue, 27 Jun 2023 12:19:10 +0100 Subject: [PATCH 02/24] Intro --- src/content/learn/typescript.md | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/content/learn/typescript.md b/src/content/learn/typescript.md index 4007ac61e0f..a25fce0bc81 100644 --- a/src/content/learn/typescript.md +++ b/src/content/learn/typescript.md @@ -1,28 +1,32 @@ --- title: Using TypeScript +re: https://github.com/reactjs/react.dev/issues/5960 --- -TypeScript is a popular way to add type definitions to React projects. Out of the box, TypeScript [supports JSX](/learn/writing-markup-with-jsx) and you can get full React support by adding [`@types/react-dom`](https://www.npmjs.com/package/@types/react-dom) to your project. +TypeScript is a popular way to add type definitions to JavaScript codebases. Out of the box, TypeScript [supports JSX](/learn/writing-markup-with-jsx) and you can get full React support by adding [`@types/react-dom`](https://www.npmjs.com/package/@types/react-dom) to your project. -* [How does ](/learn/start-a-new-react-project) +* [How does it come together](/learn/start-a-new-react-project) * [How to add React to an existing project](/learn/add-react-to-an-existing-project) * [How to set up your editor](/learn/editor-setup) * [How to install React Developer Tools](/learn/react-developer-tools) -## Try React {/*try-react*/} -You don't need to install anything to play with React. Try editing this sandbox! +All of the production-grade frameworks mentioned in [Start a New React Project](/learn/start-a-new-react-project) offer support for using TypeScript with React, we recommend consulting their documentation for more information on setup. This guide assumes you have your project configured to support writing TypeScript React files as `*.tsx`. + +## TypeScript with React {/*typescript-with-react*/} ```tsx App.tsx active +const a = ""; + function Greeting({ name } : { name: string }) { return

Hello, {name}

; } @@ -34,9 +38,12 @@ export default function App() {
-You can edit it directly or open it in a new tab by pressing the "Fork" button in the upper right corner. + + +These sandboxes can handle TypeScript code, but they do not run the type-checker. This means you can amend the TypeScript sandboxes to learn, but you won't get any type errors or warnings. To get type-checking, you can use the [TypeScript Playground](https://www.typescriptlang.org/play) or use an online sandbox. + + -Most pages in the React documentation contain sandboxes like this. Outside of the React documentation, there are many online sandboxes that support React: for example, [CodeSandbox](https://codesandbox.io/s/new), [StackBlitz](https://stackblitz.com/fork/react), or [CodePen.](https://codepen.io/pen?&editors=0010&layout=left&prefill_data_id=3f4569d1-1b11-4bce-bd46-89090eed5ddb) ### Try React locally {/*try-react-locally*/} From fe6523d250d5c48ac15c2eba32dfaaa140aed29a Mon Sep 17 00:00:00 2001 From: orta Date: Tue, 27 Jun 2023 14:20:57 +0100 Subject: [PATCH 03/24] Intro --- src/components/MDX/Sandpack/NavigationBar.tsx | 6 ++ .../Sandpack/OpenInTypeScriptPlayground.tsx | 26 +++++++++ src/content/learn/typescript.md | 58 +++++++++++++++---- 3 files changed, 80 insertions(+), 10 deletions(-) create mode 100644 src/components/MDX/Sandpack/OpenInTypeScriptPlayground.tsx diff --git a/src/components/MDX/Sandpack/NavigationBar.tsx b/src/components/MDX/Sandpack/NavigationBar.tsx index 8c884a5d8a7..39cfd8cb61c 100644 --- a/src/components/MDX/Sandpack/NavigationBar.tsx +++ b/src/components/MDX/Sandpack/NavigationBar.tsx @@ -21,6 +21,7 @@ import {ResetButton} from './ResetButton'; import {DownloadButton} from './DownloadButton'; import {IconChevron} from '../../Icon/IconChevron'; import {Listbox} from '@headlessui/react'; +import {OpenInTypeScriptPlaygroundButton} from './OpenInTypeScriptPlayground'; export function useEvent(fn: any): any { const ref = useRef(null); @@ -182,6 +183,11 @@ export function NavigationBar({providedFiles}: {providedFiles: Array}) { + {activeFile.endsWith('.tsx') && ( + + )} ); diff --git a/src/components/MDX/Sandpack/OpenInTypeScriptPlayground.tsx b/src/components/MDX/Sandpack/OpenInTypeScriptPlayground.tsx new file mode 100644 index 00000000000..f4b7ba77d2e --- /dev/null +++ b/src/components/MDX/Sandpack/OpenInTypeScriptPlayground.tsx @@ -0,0 +1,26 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + */ + +import {IconNewPage} from '../../Icon/IconNewPage'; + +export const OpenInTypeScriptPlaygroundButton = (props: {content: string}) => { + const contentWithReactImport = `import * as React from 'react';\n\n${props.content}`; + return ( + + + TypeScript Playground + + ); +}; diff --git a/src/content/learn/typescript.md b/src/content/learn/typescript.md index a25fce0bc81..1a28b207c2b 100644 --- a/src/content/learn/typescript.md +++ b/src/content/learn/typescript.md @@ -18,21 +18,30 @@ TypeScript is a popular way to add type definitions to JavaScript codebases. Out -All of the production-grade frameworks mentioned in [Start a New React Project](/learn/start-a-new-react-project) offer support for using TypeScript with React, we recommend consulting their documentation for more information on setup. This guide assumes you have your project configured to support writing TypeScript React files as `*.tsx`. +All of the production-grade frameworks mentioned in [Start a New React Project](/learn/start-a-new-react-project) offer support for using TypeScript with React, we recommend consulting their documentation for more information on setup. This guide assumes you have your project configured to support writing `*.tsx` TypeScript React files, and have finished the Quick Start guide. ## TypeScript with React {/*typescript-with-react*/} +Writing TypeScript with React is very similar to writing JavaScript with React. The key difference when working with a component is that you can provide types for your component's props. These types can be used for correctness checking and providing inline documentation in editors. + +Taking the [`MyButton` functional component](/learn#components) from the [Quick Start](/learn) guide, we can add a type describing the `title` for the button: + ```tsx App.tsx active -const a = ""; - -function Greeting({ name } : { name: string }) { - return

Hello, {name}

; +function MyButton({ title }: { title: string }) { + return ( + + ); } -export default function App() { - return +export default function MyApp() { + return ( +
+

Welcome to my app

+ +
+ ); } ``` @@ -40,14 +49,43 @@ export default function App() { -These sandboxes can handle TypeScript code, but they do not run the type-checker. This means you can amend the TypeScript sandboxes to learn, but you won't get any type errors or warnings. To get type-checking, you can use the [TypeScript Playground](https://www.typescriptlang.org/play) or use an online sandbox. +These sandboxes can handle TypeScript code, but they do not run the type-checker. This means you can amend the TypeScript sandboxes to learn, but you won't get any type errors or warnings. To get type-checking, you can use the [TypeScript Playground](https://www.typescriptlang.org/play) or use a more fully-featured online sandbox. +This inline syntax is the simplest way to provide types for a functional component, though once you start to have a few fields to describe it can become unwieldy. Instead, you can use an `interface` or `type` to describe the component's props: + + + +```tsx App.tsx active +interface MyButtonProps { + /** The text to display inside the button */ + title: string; + /** Whether the button can be interacted with */ + disabled: boolean; +} + +function MyButton({ title, disabled }: MyButtonProps) { + return ( + + ); +} + +export default function MyApp() { + return ( +
+

Welcome to my app

+ +
+ ); +} +``` + +
-### Try React locally {/*try-react-locally*/} +The type describing your component's props can be as simple or as complex as you need, though they should probably be object types. You can learn about how TypeScript describes objects in [Object Types](https://www.typescriptlang.org/docs/handbook/2/objects.html) but you may also be interested in using [Union Types](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types) to describe a prop that can be one of a few different types and the +[Creating Types from Types](https://www.typescriptlang.org/docs/handbook/2/types-from-types.html) guide for more advanced use cases. -To try React locally on your computer, [download this HTML page.](https://gist.githubusercontent.com/gaearon/0275b1e1518599bbeafcde4722e79ed1/raw/db72dcbf3384ee1708c4a07d3be79860db04bff0/example.html) Open it in your editor and in your browser! ## Start a new React project {/*start-a-new-react-project*/} From 678a7b89e9217d1109898d00cc5ad87ac5ed9e73 Mon Sep 17 00:00:00 2001 From: orta Date: Tue, 27 Jun 2023 15:26:33 +0100 Subject: [PATCH 04/24] Use State --- src/content/learn/typescript.md | 50 +++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/src/content/learn/typescript.md b/src/content/learn/typescript.md index 1a28b207c2b..34ade9b3e1c 100644 --- a/src/content/learn/typescript.md +++ b/src/content/learn/typescript.md @@ -9,9 +9,9 @@ TypeScript is a popular way to add type definitions to JavaScript codebases. Out - -* [How does it come together](/learn/start-a-new-react-project) -* [How to add React to an existing project](/learn/add-react-to-an-existing-project) + +* [TypeScript with React Components](/learn/typescript#typescript-with-react-components) +* [Typing common hooks](/learn/add-react-to-an-existing-project) * [How to set up your editor](/learn/editor-setup) * [How to install React Developer Tools](/learn/react-developer-tools) @@ -20,7 +20,7 @@ TypeScript is a popular way to add type definitions to JavaScript codebases. Out All of the production-grade frameworks mentioned in [Start a New React Project](/learn/start-a-new-react-project) offer support for using TypeScript with React, we recommend consulting their documentation for more information on setup. This guide assumes you have your project configured to support writing `*.tsx` TypeScript React files, and have finished the Quick Start guide. -## TypeScript with React {/*typescript-with-react*/} +## TypeScript with React Components {/*typescript-with-react-components*/} Writing TypeScript with React is very similar to writing JavaScript with React. The key difference when working with a component is that you can provide types for your component's props. These types can be used for correctness checking and providing inline documentation in editors. @@ -83,13 +83,47 @@ export default function MyApp() {
-The type describing your component's props can be as simple or as complex as you need, though they should probably be object types. You can learn about how TypeScript describes objects in [Object Types](https://www.typescriptlang.org/docs/handbook/2/objects.html) but you may also be interested in using [Union Types](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types) to describe a prop that can be one of a few different types and the -[Creating Types from Types](https://www.typescriptlang.org/docs/handbook/2/types-from-types.html) guide for more advanced use cases. +The type describing your component's props can be as simple or as complex as you need, though they should probably be an object type. You can learn about how TypeScript describes objects in [Object Types](https://www.typescriptlang.org/docs/handbook/2/objects.html) but you may also be interested in using [Union Types](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types) to describe a prop that can be one of a few different types and the [Creating Types from Types](https://www.typescriptlang.org/docs/handbook/2/types-from-types.html) guide for more advanced use cases. -## Start a new React project {/*start-a-new-react-project*/} +## Hooks {/*typing-hooks*/} + +The type definitions from `@types/react-dom` include types for the built-in hooks, so you can use them in your components without any additional setup. They are built to take into account the code you write in your component, so you will get inferred types a lot of the time and ideally do not need to handle the minutiae of providing the types. However, we can look at a few examples of how to provide types for hooks. + +### `useState` {/*typing-usestate*/} + +The `useState` hook will re-use the value passed in as the initial state to determine what the type of the value should be. For example: + +```ts +const [enabled, setEnabled] = useState(false); +``` + +Will assign the type of `boolean` to `enabled`, and `setEnabled` will be a function accepting either a `boolean` argument, or a function that returns a `boolean`. If you want to explicitly provide a type for the state, you can do so by providing a type argument to the `useState` call: + +```ts +const [enabled, setEnabled] = useState(false); +``` + +This isn't very useful in this case, but a common case where you may want to provide a type is when you have a union type. For example, `status` here can be one of a few different strings: + +```ts +type Status = "idle" | "loading" | "success" | "error"; + +const [status, setStatus] = useState("idle"); +``` + +Or, as recommended in [Principles for structuring state](/learn/choosing-the-state-structure#principles-for-structuring-state), you can group related state as an object and describe the different possibilities via object types: + +```ts +type RequestState = + | { status: 'idle' } + | { status: 'loading' } + | { status: 'success', data: any } + | { status: 'error', error: Error }; + +const [requestState, setRequestState] = useState({ status: 'idle' }); +``` -If you want to build an app or a website fully with React, [start a new React project.](/learn/start-a-new-react-project) ## Add React to an existing project {/*add-react-to-an-existing-project*/} From 9c17b26a9de22bdf63a96c9fc6dd505dc096b9c5 Mon Sep 17 00:00:00 2001 From: orta Date: Tue, 27 Jun 2023 16:11:03 +0100 Subject: [PATCH 05/24] Use Reducer --- src/content/learn/typescript.md | 84 ++++++++++++++++++++++++++++++--- 1 file changed, 78 insertions(+), 6 deletions(-) diff --git a/src/content/learn/typescript.md b/src/content/learn/typescript.md index 34ade9b3e1c..5524d4c7305 100644 --- a/src/content/learn/typescript.md +++ b/src/content/learn/typescript.md @@ -45,6 +45,10 @@ export default function MyApp() { } ``` +```js App.js hidden +import AppTSX from "./App.tsx"; +export default App = AppTSX; +``` @@ -75,12 +79,17 @@ export default function MyApp() { return (

Welcome to my app

- +
); } ``` +```js App.js hidden +import AppTSX from "./App.tsx"; +export default App = AppTSX; +``` + The type describing your component's props can be as simple or as complex as you need, though they should probably be an object type. You can learn about how TypeScript describes objects in [Object Types](https://www.typescriptlang.org/docs/handbook/2/objects.html) but you may also be interested in using [Union Types](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types) to describe a prop that can be one of a few different types and the [Creating Types from Types](https://www.typescriptlang.org/docs/handbook/2/types-from-types.html) guide for more advanced use cases. @@ -92,7 +101,7 @@ The type definitions from `@types/react-dom` include types for the built-in hook ### `useState` {/*typing-usestate*/} -The `useState` hook will re-use the value passed in as the initial state to determine what the type of the value should be. For example: +The [`useState` hook](/reference/react/useReducer) will re-use the value passed in as the initial state to determine what the type of the value should be. For example: ```ts const [enabled, setEnabled] = useState(false); @@ -124,12 +133,75 @@ type RequestState = const [requestState, setRequestState] = useState({ status: 'idle' }); ``` +### `useReducer` {/*usereducer*/} -## Add React to an existing project {/*add-react-to-an-existing-project*/} +The [`useReducer` hook](/reference/react/useReducer) is a more complex hook that takes a reducer function and an initial state. The types for the reducer function are inferred from the initial state. You can optionally provide a type argument to the `useReducer` call to provide a type for the state, but it is often better to set the type on the initial state instead: -If want to try using React in your existing app or a website, [add React to an existing project.](/learn/add-react-to-an-existing-project) + + +```tsx App.tsx active +import {useReducer, useCallback} from 'react'; + +interface State { + count: number +}; + +type CounterAction = + | { type: "reset" } + | { type: "setCount"; value: State["count"] } + +const initialState: State = { count: 0 }; + +function stateReducer(state: State, action: CounterAction): State { + switch (action.type) { + case "reset": + return initialState; + case "setCount": + return { ...state, count: action.value }; + default: + throw new Error("Unknown action"); + } +} -## Next steps {/*next-steps*/} +export default function App() { + const [state, dispatch] = useReducer(stateReducer, initialState); -Head to the [Quick Start](/learn) guide for a tour of the most important React concepts you will encounter every day. + const addFive = useCallback(() => dispatch({ type: "setCount", value: state.count + 5 }), [state.count]); + const reset = useCallback(() => dispatch({ type: "reset" }), []); + return ( +
+

Welcome to my counter

+ +

Count: {state.count}

+ + +
+ ); +} + +``` + +```js App.js hidden +import AppTSX from "./App.tsx"; +export default App = AppTSX; +``` +
+ + +We are using TypeScript in a few key places: + + - `interface State` describes the shape of the reducer's state. + - `type CounterAction` describes the different actions which can be dispatched to the reducer. + - `const initialState: State` provides a type for the initial state, and also the type which is used by `useReducer` by default. + - `stateReducer(state: State, action: CounterAction): State` sets the types for the reducer function's arguments and return value. + + An alternative to setting the type on `initialState` is to provide a type argument to `useReducer`: + + ```ts +const initialState = { count: 0 }; + +export default function App() { + const [state, dispatch] = useReducer(stateReducer, initialState); +} + ``` From b9bd62169a9843bf0fee8c9be0ce5c81df889e15 Mon Sep 17 00:00:00 2001 From: orta Date: Tue, 27 Jun 2023 16:18:51 +0100 Subject: [PATCH 06/24] Start of context --- src/content/learn/typescript.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/content/learn/typescript.md b/src/content/learn/typescript.md index 5524d4c7305..2d508551bba 100644 --- a/src/content/learn/typescript.md +++ b/src/content/learn/typescript.md @@ -11,7 +11,7 @@ TypeScript is a popular way to add type definitions to JavaScript codebases. Out * [TypeScript with React Components](/learn/typescript#typescript-with-react-components) -* [Typing common hooks](/learn/add-react-to-an-existing-project) +* [Typing common hooks](/learn/typescript#typing-hooks) * [How to set up your editor](/learn/editor-setup) * [How to install React Developer Tools](/learn/react-developer-tools) @@ -133,7 +133,7 @@ type RequestState = const [requestState, setRequestState] = useState({ status: 'idle' }); ``` -### `useReducer` {/*usereducer*/} +### `useReducer` {/*typing-usereducer*/} The [`useReducer` hook](/reference/react/useReducer) is a more complex hook that takes a reducer function and an initial state. The types for the reducer function are inferred from the initial state. You can optionally provide a type argument to the `useReducer` call to provide a type for the state, but it is often better to set the type on the initial state instead: @@ -196,12 +196,16 @@ We are using TypeScript in a few key places: - `const initialState: State` provides a type for the initial state, and also the type which is used by `useReducer` by default. - `stateReducer(state: State, action: CounterAction): State` sets the types for the reducer function's arguments and return value. - An alternative to setting the type on `initialState` is to provide a type argument to `useReducer`: +A more explicit alternative to setting the type on `initialState` is to provide a type argument to `useReducer`: - ```ts +```ts const initialState = { count: 0 }; export default function App() { const [state, dispatch] = useReducer(stateReducer, initialState); } - ``` +``` + +### `useContext` {/*typing-usecontext*/} + +The [`useContext` hook](/reference/react/useContext) is a [...] From bbe4652e00b57165a2063af4c89e66ad6667cd51 Mon Sep 17 00:00:00 2001 From: Orta Therox Date: Tue, 27 Jun 2023 21:18:25 +0100 Subject: [PATCH 07/24] Use Ref --- src/content/learn/typescript.md | 127 +++++++++++++++++++++++++++++++- 1 file changed, 126 insertions(+), 1 deletion(-) diff --git a/src/content/learn/typescript.md b/src/content/learn/typescript.md index 2d508551bba..d89cee2bcbd 100644 --- a/src/content/learn/typescript.md +++ b/src/content/learn/typescript.md @@ -10,6 +10,7 @@ TypeScript is a popular way to add type definitions to JavaScript codebases. Out + * [TypeScript with React Components](/learn/typescript#typescript-with-react-components) * [Typing common hooks](/learn/typescript#typing-hooks) * [How to set up your editor](/learn/editor-setup) @@ -186,6 +187,7 @@ export default function App() { import AppTSX from "./App.tsx"; export default App = AppTSX; ``` + @@ -208,4 +210,127 @@ export default function App() { ### `useContext` {/*typing-usecontext*/} -The [`useContext` hook](/reference/react/useContext) is a [...] +The [`useContext` hook](/reference/react/useContext) is a technique for passing data down the component tree without having to pass props through components. It is used by creating a provider component and often by creating a hook to consume the value in a child component. + +The type of the value provided by the context is inferred from the value passed to the `createContext` call: + + + +```tsx App.tsx active +import { createContext, useContext, useState } from 'react'; + +type Theme = "light" | "dark" | "system"; +const ThemeContext = createContext("system"); + +const useGetTheme = () => useContext(ThemeContext); + +export default function MyApp() { + const [theme, setTheme] = useState('light'); + + return ( + + + + ) +} + +function MyComponent() { + const theme = useGetTheme(); + + return ( +
+

Current theme: {theme}

+
+ ) +} +``` + +```js App.js hidden +import AppTSX from "./App.tsx"; +export default App = AppTSX; +``` + +
+ +This technique works when you have an obvious default value - but often with context you do not, and [in those cases `null` is an appropriate default value](/reference/react/useContext#specifying-a-fallback-default-value). However, you likely would not want `null` to be in the type when consuming the type, our recommendation is to have the hook do a runtime check for it's existence and throw an error when not present: + +```js {5, 16-20} +import { createContext, useContext, useState, useMemo } from 'react'; + +// This is a simpler example, but you can imagine a more complex object here +type ComplexObject = { + kind: string +}; + +// The context is created with `| null` in the type, to accurately reflect the default value. +const Context = createContext(null); + +// The `| null` will be removed via the check in the hook. +const useGetComplexObject = () => { + const object = useContext(Context); + if (!object) { throw new Error("useGetComplexObject must be used within a Provider") } + return object; +} + +export default function MyApp() { + const object = useMemo(() => ({ kind: "complex" }), []); + + return ( + + + + ) +} + +function MyComponent() { + const object = useGetComplexObject(); + + return ( +
+

Current object: {object.kind}

+
+ ) +} +``` + +### `useRef` {/*typing-useref*/} + +The [`useRef` hook](/reference/react/useRef) returns a mutable ref object whose `.current` property is initialized to the passed argument. The returned object will persist for the full lifetime of the component. + +`useRef` is often used to access the underlying DOM element of a component, but it can also be used to store any mutable value. + +When interacting with the DOM, the type of the ref should be set to the type of the underlying DOM element. The naming rule is `HTML` + the name of the element + `Element`, for example `HTMLDivElement` or `HTMLButtonElement`. You can see the full list from TypeScript 5.1 [here](https://github.com/microsoft/TypeScript/blob/a3773ec590c4f0308d546f0e65818cd0d12402f3/src/lib/dom.generated.d.ts#L26899-L27012). These are provided globally by the "DOM" lib, which is included by default in TypeScript projects. + + + +```tsx App.tsx active +import { useRef } from 'react'; + +export default function Form() { + const inputRef = useRef(null); + + function handleClick() { + // The ?. is used because of the `| null` above. + inputRef?.current.focus(); + } + + return ( + <> + + + + ); +} +``` + +```js App.js hidden +import AppTSX from "./App.tsx"; +export default App = AppTSX; +``` + + + + +### `useMemo` / `useCallback` {/*typing-other-hooks*/} \ No newline at end of file From aa9519d7cbd9ef67bcda59d4ba60779206ec7be2 Mon Sep 17 00:00:00 2001 From: Orta Therox Date: Tue, 27 Jun 2023 21:50:05 +0100 Subject: [PATCH 08/24] Events --- src/content/learn/typescript.md | 53 +++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/src/content/learn/typescript.md b/src/content/learn/typescript.md index d89cee2bcbd..1bf4804dc70 100644 --- a/src/content/learn/typescript.md +++ b/src/content/learn/typescript.md @@ -13,8 +13,7 @@ TypeScript is a popular way to add type definitions to JavaScript codebases. Out * [TypeScript with React Components](/learn/typescript#typescript-with-react-components) * [Typing common hooks](/learn/typescript#typing-hooks) -* [How to set up your editor](/learn/editor-setup) -* [How to install React Developer Tools](/learn/react-developer-tools) +* [Typing Events](/learn/typescript/#typing-dom-events)
@@ -141,7 +140,7 @@ The [`useReducer` hook](/reference/react/useReducer) is a more complex hook that ```tsx App.tsx active -import {useReducer, useCallback} from 'react'; +import {useReducer} from 'react'; interface State { count: number @@ -167,8 +166,8 @@ function stateReducer(state: State, action: CounterAction): State { export default function App() { const [state, dispatch] = useReducer(stateReducer, initialState); - const addFive = useCallback(() => dispatch({ type: "setCount", value: state.count + 5 }), [state.count]); - const reset = useCallback(() => dispatch({ type: "reset" }), []); + const addFive = () => dispatch({ type: "setCount", value: state.count + 5 }); + const reset = () => dispatch({ type: "reset" }); return (
@@ -333,4 +332,46 @@ export default App = AppTSX; -### `useMemo` / `useCallback` {/*typing-other-hooks*/} \ No newline at end of file +### `useMemo` / `useCallback` {/*typing-memo-callback*/} + +The [`useMemo`](/reference/react/useMemo) and [`useCallback`](/reference/react/useCallback) hooks follow the same pattern with determining their type from the parameter passed to them. If needed you can pass a type argument to them to explicitly set the type. + +`useCallback` requires adding your + +### `useEffect` {/*typing-useeffect*/} + +The [`useEffect` hook](/reference/react/useEffect) is used to perform side effects in a component. It is called after every render by default, but can be configured to only run when certain values change. The types for this hook allow for either returning a cleanup function or not returning anything. + +## Typing DOM Events {/*typing-dom-events*/} + +When working with DOM events in React, the type of the event is inferred from the event handler. However, when you want to extract a function to be passed to an event handler, you will need to explicitly set the type of the event. + + + +```tsx App.tsx active +import { useState } from 'react'; + +export default function Form() { + const [value, setValue] = useState("Change me"); + + function handleChange(event: React.ChangeEvent) { + setValue(event.target.value); + } + + return ( + <> + +

Value: {value}

+ + ); +} +``` + +```js App.js hidden +import AppTSX from "./App.tsx"; +export default App = AppTSX; +``` + +
+ +There are many types of events provided in React - the full list can be found [here](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/b580df54c0819ec9df62b0835a315dd48b8594a9/types/react/index.d.ts#L1247C1-L1373) which is based on the [most popular events from the DOM](https://developer.mozilla.org/en-US/docs/Web/Events). If you need to use an event that is not included in this list, you can use the `React.SyntheticEvent` type, which is the base type for all events. From 3285dfb84dedf0f079dec382831169ee6e6f5456 Mon Sep 17 00:00:00 2001 From: orta Date: Wed, 28 Jun 2023 09:49:49 +0100 Subject: [PATCH 09/24] Wrap up 1st draft --- src/content/learn/typescript.md | 60 +++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/src/content/learn/typescript.md b/src/content/learn/typescript.md index 1bf4804dc70..ef28cd0b798 100644 --- a/src/content/learn/typescript.md +++ b/src/content/learn/typescript.md @@ -342,7 +342,11 @@ The [`useMemo`](/reference/react/useMemo) and [`useCallback`](/reference/react/u The [`useEffect` hook](/reference/react/useEffect) is used to perform side effects in a component. It is called after every render by default, but can be configured to only run when certain values change. The types for this hook allow for either returning a cleanup function or not returning anything. -## Typing DOM Events {/*typing-dom-events*/} +## Useful Types {/*useful-types*/} + +There is quite an expansive set of types which come from the `@types/react` package, it is worth a read when you feel comfortable with how React and TypeScript interact. You can find them [in React's folder in DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts). We will cover a few of the more common types here. + +### DOM Events {/*typing-dom-events*/} When working with DOM events in React, the type of the event is inferred from the event handler. However, when you want to extract a function to be passed to an event handler, you will need to explicitly set the type of the event. @@ -374,4 +378,56 @@ export default App = AppTSX; -There are many types of events provided in React - the full list can be found [here](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/b580df54c0819ec9df62b0835a315dd48b8594a9/types/react/index.d.ts#L1247C1-L1373) which is based on the [most popular events from the DOM](https://developer.mozilla.org/en-US/docs/Web/Events). If you need to use an event that is not included in this list, you can use the `React.SyntheticEvent` type, which is the base type for all events. +There are many types of events provided in the React types - the full list can be found [here](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/b580df54c0819ec9df62b0835a315dd48b8594a9/types/react/index.d.ts#L1247C1-L1373) which is based on the [most popular events from the DOM](https://developer.mozilla.org/en-US/docs/Web/Events). If you need to use an event that is not included in this list, you can use the `React.SyntheticEvent` type, which is the base type for all events. + +### Children {/*typing-children*/} + +There are three common paths to describing the children of a component. The first is to use the `React.ReactNode` type, which is a union of all the possible types that can be passed as children in JSX: + +```ts +interface ModalRendererProps { + title: string; + children: React.ReactNode; +} +``` + +The second is to use the `React.ReactElement` type, which is only JSX elements and not JavaScript primitives like strings or numbers: + +```ts +interface ModalRendererProps { + title: string; + children: React.ReactElement; +} +``` + +The third is to use `React.PropsWithChildren` which is a utility type that takes an object type and adds a optional `children` field of `React.ReactNode` to it: + +```ts +type ModalRendererProps = React.PropsWithChildren<{ + title: string; +}> +``` + +Note, that you cannot use TypeScript to describe that the children are a certain type of elements. You can see all three of these in action with the type-checker in [this TypeScript playground](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgIilQ3wChSB6CxYmAOmXRgDkIATJOdNJMGAZzgwAFpxAR+8YADswAVwGkZMJFEzpOjDKw4AFHGEEBvUnDhphwADZsi0gFw0mDWjqQBuUgF9yaCNMlENzgAXjgACjADfkctFnYkfQhDAEpQgD44AB42YAA3dKMo5P46C2tbJGkvLIpcgt9-QLi3AEEwMFCItJDMrPTTbIQ3dKywdIB5aU4kKyQQKpha8drhhIGzLLWODbNs3b3s8YAxKBQAcwXpAThMaGWDvbH0gFloGbmrgQfBzYpd1YjQZbEYARkB6zMwO2SHSAAlZlYIBCdtCRkZpHIrFYahQYQD8UYYFA5EhcfjyGYqHAXnJAsIUHlOOUbHYhMIIHJzsI0Qk4P9SLUBuRqXEXEwAKKfRZcNA8PiCfxWACecAAUgBlAAacFm80W-CU11U6h4TgwUv11yShjgJjMLMqDnN9Dilq+nh8pD8AXgCHdMrCkWisVoAet0R6fXqhWKhjKllZVVxMcavpd4Zg7U6Qaj+2hmdG4zeRF10uu-Aeq0LBfLMEe-V+T2L7zLVu+FBWLdLeq+lc7DYFf39deFVOotMCACNOCh1dq219a+30uC8YWoZsRyuEdjkevR8uvoVMdjyTWt4WiSSydXD4NqZP4AymeZE072ZzuUeZQKheRKGoMUbX4AB1YARAAYXfNlgEEJkoFVbheBgGRzjgGQMNkBQABpzAgBC0K4bE4AgTAXWCFBpDYOBpAgN8Kjsb0mj9cCoPfKoumDEpQ2cEC2OEaDGKqLIjC8dI8xyfJY2iBNhOqWpU2Y9M4gEoSk2kbMuMkgk1I46Qi1eVtewNKs8T0ioql0iDBP0htHk2bsPnbfsuyMns61cwcAXMmz1I4AzKSGCybCstcEBCgLMjgaFIqs3ckVWOLAq3ZKTyxHEkr8uzYuyyyDOvUlyTSoLqQASRwaRgDQFBsVVO4oHZThpBQBY8Jq6RiP4ei6OfRlmRgqpcvY-L+QGf8gA). + +### Style Props {/*typing-style-props*/} + +When using inline styles in React, you can use `React.CSSProperties` to describe the object passed to the `style` prop. This type is a union of all the possible CSS properties, and is a good way to ensure you are passing valid CSS properties to the `style` prop, and to get auto-complete in your editor. + +```ts +interface MyComponentProps { + style: React.CSSProperties; +} +``` + +## Further learning {/*further-learning*/} + +This guide has covered the basics of using TypeScript with React, but there is a lot more to learn. We recommend the following resources: + + - [The TypeScript handbook](https://www.typescriptlang.org/docs/handbook/) is the official documentation for TypeScript, and covers most key language features. + + - [The TypeScript release notes](https://devblogs.microsoft.com/typescript/) covers a each new features in-depth. + + - [React TypeScript Cheatsheet](https://react-typescript-cheatsheet.netlify.app/) is a community-maintained cheatsheet for using TypeScript with React, covering a lot of useful edge cases and providing more breadth than this document. + + - [TypeScript Community Discord](discord.com/invite/typescript) is a great place to ask questions and get help with TypeScript and React issues. \ No newline at end of file From 315258fbbde97ce12547004d8583254b857d8e44 Mon Sep 17 00:00:00 2001 From: orta Date: Wed, 28 Jun 2023 09:55:52 +0100 Subject: [PATCH 10/24] Better titles --- src/content/learn/typescript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/typescript.md b/src/content/learn/typescript.md index ef28cd0b798..d5541c1d5be 100644 --- a/src/content/learn/typescript.md +++ b/src/content/learn/typescript.md @@ -13,7 +13,7 @@ TypeScript is a popular way to add type definitions to JavaScript codebases. Out * [TypeScript with React Components](/learn/typescript#typescript-with-react-components) * [Typing common hooks](/learn/typescript#typing-hooks) -* [Typing Events](/learn/typescript/#typing-dom-events) +* [Common types from `@types/react`](/learn/typescript/#useful-types) From a08f52b6e08a4e0682017f5ad9bb068833b90348 Mon Sep 17 00:00:00 2001 From: Orta Therox Date: Wed, 28 Jun 2023 17:13:55 +0100 Subject: [PATCH 11/24] Apply suggestions from code review Co-authored-by: Tom Sherman Co-authored-by: Lenz Weber-Tronic --- src/content/learn/typescript.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/content/learn/typescript.md b/src/content/learn/typescript.md index d5541c1d5be..7244c4eca79 100644 --- a/src/content/learn/typescript.md +++ b/src/content/learn/typescript.md @@ -101,7 +101,7 @@ The type definitions from `@types/react-dom` include types for the built-in hook ### `useState` {/*typing-usestate*/} -The [`useState` hook](/reference/react/useReducer) will re-use the value passed in as the initial state to determine what the type of the value should be. For example: +The [`useState` hook](/reference/react/useState) will re-use the value passed in as the initial state to determine what the type of the value should be. For example: ```ts const [enabled, setEnabled] = useState(false); @@ -359,7 +359,7 @@ export default function Form() { const [value, setValue] = useState("Change me"); function handleChange(event: React.ChangeEvent) { - setValue(event.target.value); + setValue(event.currentTarget.value); } return ( From 0f29e56a01f6d470342937f20640269681561812 Mon Sep 17 00:00:00 2001 From: orta Date: Mon, 3 Jul 2023 15:33:39 +0100 Subject: [PATCH 12/24] Note types/react and types/react-dom, and tone down the usecontext null check --- src/content/learn/typescript.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/content/learn/typescript.md b/src/content/learn/typescript.md index 7244c4eca79..ed106ad629a 100644 --- a/src/content/learn/typescript.md +++ b/src/content/learn/typescript.md @@ -5,7 +5,7 @@ re: https://github.com/reactjs/react.dev/issues/5960 -TypeScript is a popular way to add type definitions to JavaScript codebases. Out of the box, TypeScript [supports JSX](/learn/writing-markup-with-jsx) and you can get full React support by adding [`@types/react-dom`](https://www.npmjs.com/package/@types/react-dom) to your project. +TypeScript is a popular way to add type definitions to JavaScript codebases. Out of the box, TypeScript [supports JSX](/learn/writing-markup-with-jsx) and you can get full React Web support by adding [`@types/react`](https://www.npmjs.com/package/@types/react) and [`@types/react-dom`](https://www.npmjs.com/package/@types/react-dom) to your project. @@ -97,7 +97,7 @@ The type describing your component's props can be as simple or as complex as you ## Hooks {/*typing-hooks*/} -The type definitions from `@types/react-dom` include types for the built-in hooks, so you can use them in your components without any additional setup. They are built to take into account the code you write in your component, so you will get inferred types a lot of the time and ideally do not need to handle the minutiae of providing the types. However, we can look at a few examples of how to provide types for hooks. +The type definitions from `@types/react` include types for the built-in hooks, so you can use them in your components without any additional setup. They are built to take into account the code you write in your component, so you will get inferred types a lot of the time and ideally do not need to handle the minutiae of providing the types. However, we can look at a few examples of how to provide types for hooks. ### `useState` {/*typing-usestate*/} @@ -251,7 +251,9 @@ export default App = AppTSX; -This technique works when you have an obvious default value - but often with context you do not, and [in those cases `null` is an appropriate default value](/reference/react/useContext#specifying-a-fallback-default-value). However, you likely would not want `null` to be in the type when consuming the type, our recommendation is to have the hook do a runtime check for it's existence and throw an error when not present: +This technique works when you have an default value which makes sense - but there are occasionally cases when you do not, and in those cases `null` can feel reasonable as a default value. However, to allow the type-system to understand your code, you need to explicitly set `ContextShape | null` on the `createContext`. + +This causes the knock-on issue that you need to eliminate the `| null` in the type for context consumers. Our recommendation is to have the hook do a runtime check for it's existence and throw an error when not present: ```js {5, 16-20} import { createContext, useContext, useState, useMemo } from 'react'; From 7e0d18543012e52ccfdf93bcef912fb96e7e744d Mon Sep 17 00:00:00 2001 From: orta Date: Mon, 3 Jul 2023 15:45:45 +0100 Subject: [PATCH 13/24] Feedback --- src/content/learn/typescript.md | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/content/learn/typescript.md b/src/content/learn/typescript.md index ed106ad629a..39f1dd1c91f 100644 --- a/src/content/learn/typescript.md +++ b/src/content/learn/typescript.md @@ -92,7 +92,7 @@ export default App = AppTSX; -The type describing your component's props can be as simple or as complex as you need, though they should probably be an object type. You can learn about how TypeScript describes objects in [Object Types](https://www.typescriptlang.org/docs/handbook/2/objects.html) but you may also be interested in using [Union Types](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types) to describe a prop that can be one of a few different types and the [Creating Types from Types](https://www.typescriptlang.org/docs/handbook/2/types-from-types.html) guide for more advanced use cases. +The type describing your component's props can be as simple or as complex as you need, though they should be an object type described with either a `type` or `interface`. You can learn about how TypeScript describes objects in [Object Types](https://www.typescriptlang.org/docs/handbook/2/objects.html) but you may also be interested in using [Union Types](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types) to describe a prop that can be one of a few different types and the [Creating Types from Types](https://www.typescriptlang.org/docs/handbook/2/types-from-types.html) guide for more advanced use cases. ## Hooks {/*typing-hooks*/} @@ -300,7 +300,9 @@ The [`useRef` hook](/reference/react/useRef) returns a mutable ref object whose `useRef` is often used to access the underlying DOM element of a component, but it can also be used to store any mutable value. -When interacting with the DOM, the type of the ref should be set to the type of the underlying DOM element. The naming rule is `HTML` + the name of the element + `Element`, for example `HTMLDivElement` or `HTMLButtonElement`. You can see the full list from TypeScript 5.1 [here](https://github.com/microsoft/TypeScript/blob/a3773ec590c4f0308d546f0e65818cd0d12402f3/src/lib/dom.generated.d.ts#L26899-L27012). These are provided globally by the "DOM" lib, which is included by default in TypeScript projects. +When interacting with the DOM, the type of the ref should be set to the type of the underlying DOM element. The type names match the names provided in the HTML specification. A rough heuristic is `HTML` + the name of the element + `Element`, for example `HTMLDivElement` or `HTMLButtonElement`. You can see the full [list from TypeScript 5.1 here](https://github.com/microsoft/TypeScript/blob/a3773ec590c4f0308d546f0e65818cd0d12402f3/src/lib/dom.generated.d.ts#L26899-L27012) and the [list in MDN here](https://developer.mozilla.org/en-US/docs/Web/API#h_2). + +These types are provided globally by the "DOM" lib, which is included by default in TypeScript projects and do not need to be imported. @@ -350,7 +352,9 @@ There is quite an expansive set of types which come from the `@types/react` pack ### DOM Events {/*typing-dom-events*/} -When working with DOM events in React, the type of the event is inferred from the event handler. However, when you want to extract a function to be passed to an event handler, you will need to explicitly set the type of the event. +When working with DOM events in React, the type of the event can often be inferred from the event handler. However, when you want to extract a function to be passed to an event handler, you will need to explicitly set the type of the event. + + @@ -384,7 +388,7 @@ There are many types of events provided in the React types - the full list can b ### Children {/*typing-children*/} -There are three common paths to describing the children of a component. The first is to use the `React.ReactNode` type, which is a union of all the possible types that can be passed as children in JSX: +There are two common paths to describing the children of a component. The first is to use the `React.ReactNode` type, which is a union of all the possible types that can be passed as children in JSX: ```ts interface ModalRendererProps { @@ -393,7 +397,7 @@ interface ModalRendererProps { } ``` -The second is to use the `React.ReactElement` type, which is only JSX elements and not JavaScript primitives like strings or numbers: +This is a very broad definition of children. The second is to use the `React.ReactElement` type, which is only JSX elements and not JavaScript primitives like strings or numbers: ```ts interface ModalRendererProps { @@ -402,15 +406,9 @@ interface ModalRendererProps { } ``` -The third is to use `React.PropsWithChildren` which is a utility type that takes an object type and adds a optional `children` field of `React.ReactNode` to it: - -```ts -type ModalRendererProps = React.PropsWithChildren<{ - title: string; -}> -``` +Note, that you cannot use TypeScript to describe that the children are a certain type of JSX elements, so you cannot use the type-system to describe a component which only accepts `
  • ` children. -Note, that you cannot use TypeScript to describe that the children are a certain type of elements. You can see all three of these in action with the type-checker in [this TypeScript playground](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgIilQ3wChSB6CxYmAOmXRgDkIATJOdNJMGAZzgwAFpxAR+8YADswAVwGkZMJFEzpOjDKw4AFHGEEBvUnDhphwADZsi0gFw0mDWjqQBuUgF9yaCNMlENzgAXjgACjADfkctFnYkfQhDAEpQgD44AB42YAA3dKMo5P46C2tbJGkvLIpcgt9-QLi3AEEwMFCItJDMrPTTbIQ3dKywdIB5aU4kKyQQKpha8drhhIGzLLWODbNs3b3s8YAxKBQAcwXpAThMaGWDvbH0gFloGbmrgQfBzYpd1YjQZbEYARkB6zMwO2SHSAAlZlYIBCdtCRkZpHIrFYahQYQD8UYYFA5EhcfjyGYqHAXnJAsIUHlOOUbHYhMIIHJzsI0Qk4P9SLUBuRqXEXEwAKKfRZcNA8PiCfxWACecAAUgBlAAacFm80W-CU11U6h4TgwUv11yShjgJjMLMqDnN9Dilq+nh8pD8AXgCHdMrCkWisVoAet0R6fXqhWKhjKllZVVxMcavpd4Zg7U6Qaj+2hmdG4zeRF10uu-Aeq0LBfLMEe-V+T2L7zLVu+FBWLdLeq+lc7DYFf39deFVOotMCACNOCh1dq219a+30uC8YWoZsRyuEdjkevR8uvoVMdjyTWt4WiSSydXD4NqZP4AymeZE072ZzuUeZQKheRKGoMUbX4AB1YARAAYXfNlgEEJkoFVbheBgGRzjgGQMNkBQABpzAgBC0K4bE4AgTAXWCFBpDYOBpAgN8Kjsb0mj9cCoPfKoumDEpQ2cEC2OEaDGKqLIjC8dI8xyfJY2iBNhOqWpU2Y9M4gEoSk2kbMuMkgk1I46Qi1eVtewNKs8T0ioql0iDBP0htHk2bsPnbfsuyMns61cwcAXMmz1I4AzKSGCybCstcEBCgLMjgaFIqs3ckVWOLAq3ZKTyxHEkr8uzYuyyyDOvUlyTSoLqQASRwaRgDQFBsVVO4oHZThpBQBY8Jq6RiP4ei6OfRlmRgqpcvY-L+QGf8gA). +You can see all an example of both `React.ReactNode` and `React.ReactElement` with the type-checker in [this TypeScript playground](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgIilQ3wChSB6CxYmAOmXRgDkIATJOdNJMGAZzgwAFpxAR+8YADswAVwGkZMJFEzpOjDKw4AFHGEEBvUnDhphwADZsi0gFw0mDWjqQBuUgF9yaCNMlENzgAXjgACjADfkctFnYkfQhDAEpQgD44AB42YAA3dKMo5P46C2tbJGkvLIpcgt9-QLi3AEEwMFCItJDMrPTTbIQ3dKywdIB5aU4kKyQQKpha8drhhIGzLLWODbNs3b3s8YAxKBQAcwXpAThMaGWDvbH0gFloGbmrgQfBzYpd1YjQZbEYARkB6zMwO2SHSAAlZlYIBCdtCRkZpHIrFYahQYQD8UYYFA5EhcfjyGYqHAXnJAsIUHlOOUbHYhMIIHJzsI0Qk4P9SLUBuRqXEXEwAKKfRZcNA8PiCfxWACecAAUgBlAAacFm80W-CU11U6h4TgwUv11yShjgJjMLMqDnN9Dilq+nh8pD8AXgCHdMrCkWisVoAet0R6fXqhWKhjKllZVVxMcavpd4Zg7U6Qaj+2hmdG4zeRF10uu-Aeq0LBfLMEe-V+T2L7zLVu+FBWLdLeq+lc7DYFf39deFVOotMCACNOCh1dq219a+30uC8YWoZsRyuEdjkevR8uvoVMdjyTWt4WiSSydXD4NqZP4AymeZE072ZzuUeZQKheQgA). ### Style Props {/*typing-style-props*/} From 2002ffb407e078a208125cb7c55f14e42fa00254 Mon Sep 17 00:00:00 2001 From: orta Date: Mon, 3 Jul 2023 16:30:51 +0100 Subject: [PATCH 14/24] Given a 2nd run through of the doc --- src/content/learn/typescript.md | 59 ++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 9 deletions(-) diff --git a/src/content/learn/typescript.md b/src/content/learn/typescript.md index 39f1dd1c91f..4ac6f9e80f8 100644 --- a/src/content/learn/typescript.md +++ b/src/content/learn/typescript.md @@ -14,6 +14,7 @@ TypeScript is a popular way to add type definitions to JavaScript codebases. Out * [TypeScript with React Components](/learn/typescript#typescript-with-react-components) * [Typing common hooks](/learn/typescript#typing-hooks) * [Common types from `@types/react`](/learn/typescript/#useful-types) +* [Further learning locations](/learn/typescript/#further-learning) @@ -296,9 +297,9 @@ function MyComponent() { ### `useRef` {/*typing-useref*/} -The [`useRef` hook](/reference/react/useRef) returns a mutable ref object whose `.current` property is initialized to the passed argument. The returned object will persist for the full lifetime of the component. +The [`useRef` hook](/reference/react/useRef) returns a reference object (ref) whose `.current` property is initialized to the passed argument. The returned object will persist for the full lifetime of the component. It is often used to access the underlying DOM element in a component, but it can also be used to store any values where changes should not cause re-renders. -`useRef` is often used to access the underlying DOM element of a component, but it can also be used to store any mutable value. +The inferred types for `useRef` will either provide you with a mutable ref, or an immutable ref based on whether `null` is passed as the initial value (or explicitly included in a union with the type you want to use). An immutable ref cannot have `.current` changed by your code, but it can be set by React via the `ref={ref}` API. When interacting with the DOM, the type of the ref should be set to the type of the underlying DOM element. The type names match the names provided in the HTML specification. A rough heuristic is `HTML` + the name of the element + `Element`, for example `HTMLDivElement` or `HTMLButtonElement`. You can see the full [list from TypeScript 5.1 here](https://github.com/microsoft/TypeScript/blob/a3773ec590c4f0308d546f0e65818cd0d12402f3/src/lib/dom.generated.d.ts#L26899-L27012) and the [list in MDN here](https://developer.mozilla.org/en-US/docs/Web/API#h_2). @@ -336,15 +337,53 @@ export default App = AppTSX; -### `useMemo` / `useCallback` {/*typing-memo-callback*/} +### `useMemo` {/*typing-usememo*/} -The [`useMemo`](/reference/react/useMemo) and [`useCallback`](/reference/react/useCallback) hooks follow the same pattern with determining their type from the parameter passed to them. If needed you can pass a type argument to them to explicitly set the type. +The [`useMemo`](/reference/react/useMemo) hooks will create/re-access a memorized value from a function call, re-running the function only when dependencies passed as the 2nd parameter are changed. The result of calling the hook is inferred from the return value from the function in the first parameter. You can be more explicit by providing a type argument to the hook. -`useCallback` requires adding your +```ts +// The type of visibleTodos is inferred from the return value of filterTodos +const visibleTodos = useMemo(() => filterTodos(todos, tab), [todos, tab]); +``` + + +### `useCallback` {/*typing-usecallback*/} + +The [`useCallback`](/reference/react/useCallback) provide a stable reference to a function as long as the dependencies passed into the second parameter are the same. Like `useMemo`, the function's type is inferred from the return value of the function in the first parameter, and you can be more explicit by providing a type argument to the hook. + + +```ts +const handleClick = useCallback(() => { + // ... +}, [todos]); +``` + +When working in TypeScript strict mode `useCallback` requires adding types for the parameters in your callback. This is because the type of the callback is inferred from the return value of the function, and without parameters the type cannot be fully understood. + +Depending on your code-style preferences, you could use the `*EventHandler` functions from the React types to provide the type for the event handler at the same time as defining the callback: + +```ts +import { useState, useCallback } from 'react'; + +export default function Form() { + const [value, setValue] = useState("Change me"); + + const handleChange = useCallback>((event) => { + setValue(event.currentTarget.value); + }, [setValue]) + + return ( + <> + +

    Value: {value}

    + + ); +} +``` ### `useEffect` {/*typing-useeffect*/} -The [`useEffect` hook](/reference/react/useEffect) is used to perform side effects in a component. It is called after every render by default, but can be configured to only run when certain values change. The types for this hook allow for either returning a cleanup function or not returning anything. +The [`useEffect` hook](/reference/react/useEffect) is used to perform side effects in a component after it has rendered. It is called after every render by default, but can be configured to only run when certain values change. The type of the function passed to `useEffect` is inferred from the return value of the function, and you can be more explicit by providing a type argument to the hook. ## Useful Types {/*useful-types*/} @@ -354,8 +393,6 @@ There is quite an expansive set of types which come from the `@types/react` pack When working with DOM events in React, the type of the event can often be inferred from the event handler. However, when you want to extract a function to be passed to an event handler, you will need to explicitly set the type of the event. - - ```tsx App.tsx active @@ -384,7 +421,11 @@ export default App = AppTSX; -There are many types of events provided in the React types - the full list can be found [here](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/b580df54c0819ec9df62b0835a315dd48b8594a9/types/react/index.d.ts#L1247C1-L1373) which is based on the [most popular events from the DOM](https://developer.mozilla.org/en-US/docs/Web/Events). If you need to use an event that is not included in this list, you can use the `React.SyntheticEvent` type, which is the base type for all events. +There are many types of events provided in the React types - the full list can be found [here](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/b580df54c0819ec9df62b0835a315dd48b8594a9/types/react/index.d.ts#L1247C1-L1373) which is based on the [most popular events from the DOM](https://developer.mozilla.org/en-US/docs/Web/Events). + +When determining the type you are looking for you can first look at the hover information for the event handler you are using, which will show the type of the event. + +If you need to use an event that is not included in this list, you can use the `React.SyntheticEvent` type, which is the base type for all events. ### Children {/*typing-children*/} From 8bb47019d01b491c7048459e5468a9113874babf Mon Sep 17 00:00:00 2001 From: Orta Therox Date: Mon, 24 Jul 2023 19:17:13 +0100 Subject: [PATCH 15/24] Apply suggestions from code review Co-authored-by: Ricky --- src/content/learn/typescript.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/content/learn/typescript.md b/src/content/learn/typescript.md index 4ac6f9e80f8..f94d47ba847 100644 --- a/src/content/learn/typescript.md +++ b/src/content/learn/typescript.md @@ -105,12 +105,14 @@ The type definitions from `@types/react` include types for the built-in hooks, s The [`useState` hook](/reference/react/useState) will re-use the value passed in as the initial state to determine what the type of the value should be. For example: ```ts +// Infer the type as "boolean" const [enabled, setEnabled] = useState(false); ``` Will assign the type of `boolean` to `enabled`, and `setEnabled` will be a function accepting either a `boolean` argument, or a function that returns a `boolean`. If you want to explicitly provide a type for the state, you can do so by providing a type argument to the `useState` call: ```ts +// Explicitly set the type to "boolean" const [enabled, setEnabled] = useState(false); ``` From 5d52e5eb5d14d7b337c774291f003b821c7cc19c Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Mon, 7 Aug 2023 18:08:37 +0200 Subject: [PATCH 16/24] Document where `State` is coming from --- src/content/learn/typescript.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/content/learn/typescript.md b/src/content/learn/typescript.md index f94d47ba847..0bbe56083fe 100644 --- a/src/content/learn/typescript.md +++ b/src/content/learn/typescript.md @@ -203,6 +203,8 @@ We are using TypeScript in a few key places: A more explicit alternative to setting the type on `initialState` is to provide a type argument to `useReducer`: ```ts +import { stateReducer, State } from './your-reducer-implementation'; + const initialState = { count: 0 }; export default function App() { From 6ca7d17f99a9b2df3dfeb7902456eecc61012d88 Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Mon, 7 Aug 2023 18:10:17 +0200 Subject: [PATCH 17/24] Link what inferred types are --- src/content/learn/typescript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/typescript.md b/src/content/learn/typescript.md index 0bbe56083fe..ed87b3ecc10 100644 --- a/src/content/learn/typescript.md +++ b/src/content/learn/typescript.md @@ -98,7 +98,7 @@ The type describing your component's props can be as simple or as complex as you ## Hooks {/*typing-hooks*/} -The type definitions from `@types/react` include types for the built-in hooks, so you can use them in your components without any additional setup. They are built to take into account the code you write in your component, so you will get inferred types a lot of the time and ideally do not need to handle the minutiae of providing the types. However, we can look at a few examples of how to provide types for hooks. +The type definitions from `@types/react` include types for the built-in hooks, so you can use them in your components without any additional setup. They are built to take into account the code you write in your component, so you will get [inferred types](https://www.typescriptlang.org/docs/handbook/type-inference.html) a lot of the time and ideally do not need to handle the minutiae of providing the types. However, we can look at a few examples of how to provide types for hooks. ### `useState` {/*typing-usestate*/} From 42fd5a4c694981f2764b87932fc190977ec32124 Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Mon, 7 Aug 2023 18:12:01 +0200 Subject: [PATCH 18/24] Remove "knock-on" We already say "cause" which makes "knock-on" a bit redundant --- src/content/learn/typescript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/typescript.md b/src/content/learn/typescript.md index ed87b3ecc10..0967c73e723 100644 --- a/src/content/learn/typescript.md +++ b/src/content/learn/typescript.md @@ -258,7 +258,7 @@ export default App = AppTSX; This technique works when you have an default value which makes sense - but there are occasionally cases when you do not, and in those cases `null` can feel reasonable as a default value. However, to allow the type-system to understand your code, you need to explicitly set `ContextShape | null` on the `createContext`. -This causes the knock-on issue that you need to eliminate the `| null` in the type for context consumers. Our recommendation is to have the hook do a runtime check for it's existence and throw an error when not present: +This causes the issue that you need to eliminate the `| null` in the type for context consumers. Our recommendation is to have the hook do a runtime check for it's existence and throw an error when not present: ```js {5, 16-20} import { createContext, useContext, useState, useMemo } from 'react'; From c0e6963a549fda1b845817d5e61ca8fe11d170b1 Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Mon, 7 Aug 2023 18:15:52 +0200 Subject: [PATCH 19/24] Move useRef TS usage to useRef reference page dropped useEffect since there's nothing specific about this hook. --- src/content/learn/typescript.md | 51 +++------------------------ src/content/reference/react/useRef.md | 39 ++++++++++++++++++++ 2 files changed, 43 insertions(+), 47 deletions(-) diff --git a/src/content/learn/typescript.md b/src/content/learn/typescript.md index 0967c73e723..db196b45d82 100644 --- a/src/content/learn/typescript.md +++ b/src/content/learn/typescript.md @@ -299,48 +299,6 @@ function MyComponent() { } ``` -### `useRef` {/*typing-useref*/} - -The [`useRef` hook](/reference/react/useRef) returns a reference object (ref) whose `.current` property is initialized to the passed argument. The returned object will persist for the full lifetime of the component. It is often used to access the underlying DOM element in a component, but it can also be used to store any values where changes should not cause re-renders. - -The inferred types for `useRef` will either provide you with a mutable ref, or an immutable ref based on whether `null` is passed as the initial value (or explicitly included in a union with the type you want to use). An immutable ref cannot have `.current` changed by your code, but it can be set by React via the `ref={ref}` API. - -When interacting with the DOM, the type of the ref should be set to the type of the underlying DOM element. The type names match the names provided in the HTML specification. A rough heuristic is `HTML` + the name of the element + `Element`, for example `HTMLDivElement` or `HTMLButtonElement`. You can see the full [list from TypeScript 5.1 here](https://github.com/microsoft/TypeScript/blob/a3773ec590c4f0308d546f0e65818cd0d12402f3/src/lib/dom.generated.d.ts#L26899-L27012) and the [list in MDN here](https://developer.mozilla.org/en-US/docs/Web/API#h_2). - -These types are provided globally by the "DOM" lib, which is included by default in TypeScript projects and do not need to be imported. - - - -```tsx App.tsx active -import { useRef } from 'react'; - -export default function Form() { - const inputRef = useRef(null); - - function handleClick() { - // The ?. is used because of the `| null` above. - inputRef?.current.focus(); - } - - return ( - <> - - - - ); -} -``` - -```js App.js hidden -import AppTSX from "./App.tsx"; -export default App = AppTSX; -``` - - - - ### `useMemo` {/*typing-usememo*/} The [`useMemo`](/reference/react/useMemo) hooks will create/re-access a memorized value from a function call, re-running the function only when dependencies passed as the 2nd parameter are changed. The result of calling the hook is inferred from the return value from the function in the first parameter. You can be more explicit by providing a type argument to the hook. @@ -385,10 +343,6 @@ export default function Form() { } ``` -### `useEffect` {/*typing-useeffect*/} - -The [`useEffect` hook](/reference/react/useEffect) is used to perform side effects in a component after it has rendered. It is called after every render by default, but can be configured to only run when certain values change. The type of the function passed to `useEffect` is inferred from the return value of the function, and you can be more explicit by providing a type argument to the hook. - ## Useful Types {/*useful-types*/} There is quite an expansive set of types which come from the `@types/react` package, it is worth a read when you feel comfortable with how React and TypeScript interact. You can find them [in React's folder in DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts). We will cover a few of the more common types here. @@ -467,7 +421,10 @@ interface MyComponentProps { ## Further learning {/*further-learning*/} -This guide has covered the basics of using TypeScript with React, but there is a lot more to learn. We recommend the following resources: +This guide has covered the basics of using TypeScript with React, but there is a lot more to learn. +Individual API pages on the docs may contain more in-depth documentation on how to use them with TypeScript. + +We recommend the following resources: - [The TypeScript handbook](https://www.typescriptlang.org/docs/handbook/) is the official documentation for TypeScript, and covers most key language features. diff --git a/src/content/reference/react/useRef.md b/src/content/reference/react/useRef.md index bdec1ec8d11..1710b502c50 100644 --- a/src/content/reference/react/useRef.md +++ b/src/content/reference/react/useRef.md @@ -538,6 +538,45 @@ Here, the `playerRef` itself is nullable. However, you should be able to convinc --- +### TypeScript {/*typescript*/} + +The inferred types for `useRef` will either provide you with a mutable ref, or an immutable ref based on whether `null` is passed as the initial value (or explicitly included in a union with the type you want to use). An immutable ref cannot have `.current` changed by your code, but it can be set by React via the `ref={ref}` API. + +When interacting with the DOM, the type of the ref should be set to the type of the underlying DOM element. The type names match the names provided in the HTML specification. A rough heuristic is `HTML` + the name of the element + `Element`, for example `HTMLDivElement` or `HTMLButtonElement`. You can see the full [list from TypeScript 5.1 here](https://github.com/microsoft/TypeScript/blob/a3773ec590c4f0308d546f0e65818cd0d12402f3/src/lib/dom.generated.d.ts#L26899-L27012) and the [list in MDN here](https://developer.mozilla.org/en-US/docs/Web/API#h_2). + +These types are provided globally by the "DOM" lib, which is included by default in TypeScript projects and do not need to be imported. + + + +```tsx App.tsx active +import { useRef } from 'react'; + +export default function Form() { + const inputRef = useRef(null); + + function handleClick() { + // The ?. is used because of the `| null` above. + inputRef?.current.focus(); + } + + return ( + <> + + + + ); +} +``` + +```js App.js hidden +import AppTSX from "./App.tsx"; +export default App = AppTSX; +``` + + + ## Troubleshooting {/*troubleshooting*/} ### I can't get a ref to a custom component {/*i-cant-get-a-ref-to-a-custom-component*/} From 26d63b3bde02f742065e5eb77a0e8c762ce79222 Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Mon, 7 Aug 2023 18:38:38 +0200 Subject: [PATCH 20/24] Add installation section --- src/content/learn/typescript.md | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/content/learn/typescript.md b/src/content/learn/typescript.md index db196b45d82..719c55a21de 100644 --- a/src/content/learn/typescript.md +++ b/src/content/learn/typescript.md @@ -18,11 +18,35 @@ TypeScript is a popular way to add type definitions to JavaScript codebases. Out +## Installation {/*installation*/} -All of the production-grade frameworks mentioned in [Start a New React Project](/learn/start-a-new-react-project) offer support for using TypeScript with React, we recommend consulting their documentation for more information on setup. This guide assumes you have your project configured to support writing `*.tsx` TypeScript React files, and have finished the Quick Start guide. +All of the production-grade frameworks mentioned in [Start a New React Project](/learn/start-a-new-react-project) offer support for using TypeScript with React, we recommend consulting their documentation for more information on setup. + +### Adding TypeScript to an existing React project {/*adding-typescript-to-an-existing-react-project*/} + +To install the latest version of React's type definitions: + +```bash +npm install @types/react @types/react-dom +``` + +Or if you’re using yarn: + +```bash +yarn add @types/react @types/react-dom +``` + +The following compiler options need to be set in your `tsconfig.json`: + +1. `dom` must be included in [`lib`](https://www.typescriptlang.org/tsconfig/#lib) (Note: If no `lib` option is specified, `dom` is included by default) +1. [`jsx`](https://www.typescriptlang.org/tsconfig/#jsx) must be set + `preserve` should suffice for most applications. + If you're publishing a library, consult the [`jsx` documentation](https://www.typescriptlang.org/tsconfig/#jsx) on what value to choose. ## TypeScript with React Components {/*typescript-with-react-components*/} +Keep in mind that every file containing JSX must use the `.tsx` file extension. + Writing TypeScript with React is very similar to writing JavaScript with React. The key difference when working with a component is that you can provide types for your component's props. These types can be used for correctness checking and providing inline documentation in editors. Taking the [`MyButton` functional component](/learn#components) from the [Quick Start](/learn) guide, we can add a type describing the `title` for the button: From 3ba1764457446db57e31843aa3dd6086a4e09377 Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Mon, 7 Aug 2023 18:44:15 +0200 Subject: [PATCH 21/24] Link to framework specific guides --- src/content/learn/typescript.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/content/learn/typescript.md b/src/content/learn/typescript.md index 719c55a21de..f85f84a47a8 100644 --- a/src/content/learn/typescript.md +++ b/src/content/learn/typescript.md @@ -20,7 +20,13 @@ TypeScript is a popular way to add type definitions to JavaScript codebases. Out ## Installation {/*installation*/} -All of the production-grade frameworks mentioned in [Start a New React Project](/learn/start-a-new-react-project) offer support for using TypeScript with React, we recommend consulting their documentation for more information on setup. +All of the production-grade frameworks mentioned in [Start a New React Project](/learn/start-a-new-react-project) offer support for using TypeScript with React. +You may want to look at the TypeScript guides for: + +- [Next.js](https://nextjs.org/docs/pages/building-your-application/configuring/typescript) +- [Remix](https://remix.run/docs/en/1.19.2/guides/typescript) +- [Gatsby](https://www.gatsbyjs.com/docs/how-to/custom-configuration/typescript/) +- [Expo](https://docs.expo.dev/guides/typescript/) ### Adding TypeScript to an existing React project {/*adding-typescript-to-an-existing-react-project*/} From 9c4e9860074f6691141f20916811af1cddfbda6f Mon Sep 17 00:00:00 2001 From: Ricky Hanlon Date: Wed, 9 Aug 2023 11:57:43 -0400 Subject: [PATCH 22/24] Edits --- src/content/learn/typescript.md | 36 ++++++++++++++++----------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/src/content/learn/typescript.md b/src/content/learn/typescript.md index f85f84a47a8..d437096e130 100644 --- a/src/content/learn/typescript.md +++ b/src/content/learn/typescript.md @@ -12,7 +12,7 @@ TypeScript is a popular way to add type definitions to JavaScript codebases. Out * [TypeScript with React Components](/learn/typescript#typescript-with-react-components) -* [Typing common hooks](/learn/typescript#typing-hooks) +* [Examples of typing with hooks](/learn/typescript#example-hooks) * [Common types from `@types/react`](/learn/typescript/#useful-types) * [Further learning locations](/learn/typescript/#further-learning) @@ -20,8 +20,7 @@ TypeScript is a popular way to add type definitions to JavaScript codebases. Out ## Installation {/*installation*/} -All of the production-grade frameworks mentioned in [Start a New React Project](/learn/start-a-new-react-project) offer support for using TypeScript with React. -You may want to look at the TypeScript guides for: +All [production-grade React frameworks](https://react-dev-git-fork-orta-typescriptpage-fbopensource.vercel.app/learn/start-a-new-react-project#production-grade-react-frameworks) offer support for using TypeScript. Follow the framework specific guide for installation: - [Next.js](https://nextjs.org/docs/pages/building-your-application/configuring/typescript) - [Remix](https://remix.run/docs/en/1.19.2/guides/typescript) @@ -32,30 +31,27 @@ You may want to look at the TypeScript guides for: To install the latest version of React's type definitions: -```bash + npm install @types/react @types/react-dom -``` - -Or if you’re using yarn: - -```bash -yarn add @types/react @types/react-dom -``` + The following compiler options need to be set in your `tsconfig.json`: -1. `dom` must be included in [`lib`](https://www.typescriptlang.org/tsconfig/#lib) (Note: If no `lib` option is specified, `dom` is included by default) -1. [`jsx`](https://www.typescriptlang.org/tsconfig/#jsx) must be set - `preserve` should suffice for most applications. +1. `dom` must be included in [`lib`](https://www.typescriptlang.org/tsconfig/#lib) (Note: If no `lib` option is specified, `dom` is included by default). +1. [`jsx`](https://www.typescriptlang.org/tsconfig/#jsx) must be set to one of the valid options. `preserve` should suffice for most applications. If you're publishing a library, consult the [`jsx` documentation](https://www.typescriptlang.org/tsconfig/#jsx) on what value to choose. ## TypeScript with React Components {/*typescript-with-react-components*/} -Keep in mind that every file containing JSX must use the `.tsx` file extension. + + +Every file containing JSX must use the `.tsx` file extension. This is a TypeScript-specific extension that tells TypeScript that this file contains JSX. + + Writing TypeScript with React is very similar to writing JavaScript with React. The key difference when working with a component is that you can provide types for your component's props. These types can be used for correctness checking and providing inline documentation in editors. -Taking the [`MyButton` functional component](/learn#components) from the [Quick Start](/learn) guide, we can add a type describing the `title` for the button: +Taking the [`MyButton` component](/learn#components) from the [Quick Start](/learn) guide, we can add a type describing the `title` for the button: @@ -88,7 +84,7 @@ These sandboxes can handle TypeScript code, but they do not run the type-checker -This inline syntax is the simplest way to provide types for a functional component, though once you start to have a few fields to describe it can become unwieldy. Instead, you can use an `interface` or `type` to describe the component's props: +This inline syntax is the simplest way to provide types for a component, though once you start to have a few fields to describe it can become unwieldy. Instead, you can use an `interface` or `type` to describe the component's props: @@ -126,9 +122,11 @@ export default App = AppTSX; The type describing your component's props can be as simple or as complex as you need, though they should be an object type described with either a `type` or `interface`. You can learn about how TypeScript describes objects in [Object Types](https://www.typescriptlang.org/docs/handbook/2/objects.html) but you may also be interested in using [Union Types](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types) to describe a prop that can be one of a few different types and the [Creating Types from Types](https://www.typescriptlang.org/docs/handbook/2/types-from-types.html) guide for more advanced use cases. -## Hooks {/*typing-hooks*/} +## Example Hooks {/*example-hooks*/} + +The type definitions from `@types/react` include types for the built-in hooks, so you can use them in your components without any additional setup. They are built to take into account the code you write in your component, so you will get [inferred types](https://www.typescriptlang.org/docs/handbook/type-inference.html) a lot of the time and ideally do not need to handle the minutiae of providing the types. -The type definitions from `@types/react` include types for the built-in hooks, so you can use them in your components without any additional setup. They are built to take into account the code you write in your component, so you will get [inferred types](https://www.typescriptlang.org/docs/handbook/type-inference.html) a lot of the time and ideally do not need to handle the minutiae of providing the types. However, we can look at a few examples of how to provide types for hooks. +However, we can look at a few examples of how to provide types for hooks. ### `useState` {/*typing-usestate*/} From 2030ed3f4d197aeacca73813b10a8eddefc61123 Mon Sep 17 00:00:00 2001 From: Ricky Hanlon Date: Wed, 9 Aug 2023 12:02:52 -0400 Subject: [PATCH 23/24] Edit footer --- src/components/Layout/Footer.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/Layout/Footer.tsx b/src/components/Layout/Footer.tsx index cd0cf25793c..4d0b066461f 100644 --- a/src/components/Layout/Footer.tsx +++ b/src/components/Layout/Footer.tsx @@ -290,7 +290,6 @@ export function Footer() { Quick Start Installation - Using TypeScript Describing the UI From c492f0877d1cb4d2b8131591965e1dd2963d1d27 Mon Sep 17 00:00:00 2001 From: Ricky Hanlon Date: Wed, 9 Aug 2023 12:04:44 -0400 Subject: [PATCH 24/24] Rm useRef docs --- src/content/reference/react/useRef.md | 39 --------------------------- 1 file changed, 39 deletions(-) diff --git a/src/content/reference/react/useRef.md b/src/content/reference/react/useRef.md index 1710b502c50..bdec1ec8d11 100644 --- a/src/content/reference/react/useRef.md +++ b/src/content/reference/react/useRef.md @@ -538,45 +538,6 @@ Here, the `playerRef` itself is nullable. However, you should be able to convinc --- -### TypeScript {/*typescript*/} - -The inferred types for `useRef` will either provide you with a mutable ref, or an immutable ref based on whether `null` is passed as the initial value (or explicitly included in a union with the type you want to use). An immutable ref cannot have `.current` changed by your code, but it can be set by React via the `ref={ref}` API. - -When interacting with the DOM, the type of the ref should be set to the type of the underlying DOM element. The type names match the names provided in the HTML specification. A rough heuristic is `HTML` + the name of the element + `Element`, for example `HTMLDivElement` or `HTMLButtonElement`. You can see the full [list from TypeScript 5.1 here](https://github.com/microsoft/TypeScript/blob/a3773ec590c4f0308d546f0e65818cd0d12402f3/src/lib/dom.generated.d.ts#L26899-L27012) and the [list in MDN here](https://developer.mozilla.org/en-US/docs/Web/API#h_2). - -These types are provided globally by the "DOM" lib, which is included by default in TypeScript projects and do not need to be imported. - - - -```tsx App.tsx active -import { useRef } from 'react'; - -export default function Form() { - const inputRef = useRef(null); - - function handleClick() { - // The ?. is used because of the `| null` above. - inputRef?.current.focus(); - } - - return ( - <> - - - - ); -} -``` - -```js App.js hidden -import AppTSX from "./App.tsx"; -export default App = AppTSX; -``` - - - ## Troubleshooting {/*troubleshooting*/} ### I can't get a ref to a custom component {/*i-cant-get-a-ref-to-a-custom-component*/}