diff --git a/README.md b/README.md index 2a5a2d56..8cfb13c5 100644 --- a/README.md +++ b/README.md @@ -158,10 +158,10 @@ - [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) + * [Slapping `any` on everything](#slapping-any-on-everything) + * [Autogenerate types](#autogenerate-types) + * [Typing Exported Hooks](#typing-exported-hooks) + * [Typing Exported Components](#typing-exported-components) - [Troubleshooting Handbook: Operators](#troubleshooting-handbook-operators) - [Troubleshooting Handbook: Utilties](#troubleshooting-handbook-utilities) - [Troubleshooting Handbook: tsconfig.json](#troubleshooting-handbook-tsconfigjson) @@ -177,7 +177,6 @@ - # Section 1: Setup TypeScript with React ## Prerequisites @@ -255,14 +254,24 @@ You should also check [the new TypeScript docs for official descriptions between # Section 2: Getting Started - ## Function Components These can be written as normal functions that take a `props` argument and return a JSX element. ```tsx -type AppProps = { message: string }; /* could also use interface */ +// Declaring type of props - see "Typing Component Props" for more examples +type AppProps = { + message: string; +}; /* use `interface` if exporting so that consumers can extend */ + +// Easiest way to declare a Function Component; return type is inferred. const App = ({ message }: AppProps) =>
{message}
; + +// you can choose annotate the return type so an error is raised if you accidentally return some other type +const App = ({ message }: AppProps): JSX.Element =>
{message}
; + +// you can also inline the type declaration; eliminates naming the prop types, but looks repetitive +const App = ({ message }: { message: string }) =>
{message}
; ```
@@ -297,11 +306,7 @@ const Title: React.FunctionComponent<{ title: string }> = ({ ```
- - -Using `React.VoidFunctionComponent` or `React.VFC` instead - - +Using `React.VoidFunctionComponent` or `React.VFC` instead As of [@types/react 16.9.48](https://github.com/DefinitelyTyped/DefinitelyTyped/pull/46643), you can also use `React.VoidFunctionComponent` or `React.VFC` type if you want to type `children` explicitly. This is an interim solution until `FunctionComponent` will accept no children by default (planned for `@types/react@^18.0.0`). @@ -377,14 +382,13 @@ const MyArrayComponent = () => (Array(5).fill(
) as any) as JSX.Element; - ## Hooks Hooks are [supported in `@types/react` from v16.8 up](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/a05cc538a42243c632f054e42eab483ebf1560ab/types/react/index.d.ts#L800-L1031). ## useState -Type inference works very well most of the time: +Type inference works very well for simple values: ```tsx const [val, toggle] = React.useState(false); @@ -403,6 +407,17 @@ const [user, setUser] = React.useState(null); setUser(newUser); ``` +You can also use type assertions if a state is initialized soon after setup and always has a value after: + +```tsx +const [user, setUser] = React.useState({} as IUser); + +// later... +setUser(newUser); +``` + +This temporarily "lies" to the TypeScript compiler that `{}` is of type `IUser`. You should follow up by setting the `user` state — if you don't, the rest of your code may rely on the fact that `user` is of type `IUser` and that may lead to runtime errors. + ## useReducer You can use [Discriminated Unions](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes-func.html#discriminated-unions) for reducer actions. Don't forget to define the return type of reducer, otherwise TypeScript will infer it. @@ -533,7 +548,7 @@ function MyComponent() {
-The second option will infer a `RefObject` instead of a `MutableRefObject`. This means there will be a type error ifyou try to assign to `ref2.current`. +The second option will infer a `RefObject` instead of a `MutableRefObject`. This means there will be a type error if you try to assign to `ref2.current`. The third option will make `ref3.current` mutable, and is intended for "instance variables" that you manage yourself. @@ -661,7 +676,6 @@ If you are writing a React Hooks library, don't forget that you should also expo - ## Class Components Within TypeScript, `React.Component` is a generic type (aka `React.Component`), so you want to provide it with (optional) prop and state type parameters: @@ -836,7 +850,6 @@ class Comp extends React.PureComponent { - ## You May Not Need `defaultProps` As per [this tweet](https://twitter.com/dan_abramov/status/1133878326358171650), defaultProps will eventually be deprecated. You can check the discussions here: @@ -936,7 +949,7 @@ export type ApparentGreetProps = JSX.LibraryManagedAttributes< >; ``` -``This will work properly, although hovering over`ApparentGreetProps`may be a little intimidating. You can reduce this boilerplate with the`ComponentProps` utility detailed below. +This will work properly, although hovering over`ApparentGreetProps`may be a little intimidating. You can reduce this boilerplate with the`ComponentProps` utility detailed below.
@@ -1047,7 +1060,6 @@ The problem with this approach is it causes complex issues with the type inferen - ## Typing Component Props This is intended as a basic orientation and reference for React developers familiarizing with TypeScript. @@ -1279,7 +1291,6 @@ class Comp extends React.PureComponent { - ## Forms and Events If performance is not an issue (and it usually isn't!), inlining handlers is easiest as you can just use [type inference and contextual typing](https://www.typescriptlang.org/docs/handbook/type-inference.html#contextual-typing): @@ -1340,7 +1351,7 @@ The first method uses an inferred method signature `(e: React.FormEvent`, `