├── README.md └── event-handler.png /README.md: -------------------------------------------------------------------------------- 1 | # Simple React Typescript Cheatsheet 2 | 3 | - [Simple React Typescript Cheatsheet](#simple-react-typescript-cheatsheet) 4 | - [Typing props with inline type](#typing-props-with-inline-type) 5 | - [Typing props with Type](#typing-props-with-type) 6 | - [Typing props with default value](#typing-props-with-default-value) 7 | - [Typing props with children](#typing-props-with-children) 8 | - [Using Native HTML props to React Components](#using-native-html-props-to-react-components) 9 | - [1. Basic](#1-basic) 10 | - [2. Combine with your type](#2-combine-with-your-type) 11 | - [3. Overriding Native Props](#3-overriding-native-props) 12 | - [4. Extracting Props from Custom Components](#4-extracting-props-from-custom-components) 13 | - [Typing Event Handlers from native element](#typing-event-handlers-from-native-element) 14 | - [useState](#usestate) 15 | - [useCallback](#usecallback) 16 | - [useRef](#useref) 17 | - [Basic useRef](#basic-useref) 18 | - [useRef with HTML element](#useref-with-html-element) 19 | - [useRef with forwardRef](#useref-with-forwardref) 20 | - [Making a Read-Only Ref Mutable](#making-a-read-only-ref-mutable) 21 | - [useReducer](#usereducer) 22 | - [Context](#context) 23 | - [Polymorphic](#polymorphic) 24 | - [Types or Interfaces?](#types-or-interfaces) 25 | - [Resources](#resources) 26 | 27 | 28 | ## Typing props with inline type 29 | 30 | ```tsx 31 | function Button(props: { children: React.ReactNode }) { 32 | return ; 33 | } 34 | ``` 35 | 36 | ## Typing props with Type 37 | 38 | ```tsx 39 | // you can use interface too 40 | type ButtonProps = { 41 | className: string; 42 | children: React.ReactNode; 43 | }; 44 | 45 | function Button(props: ButtonProps) { 46 | return ; 47 | } 48 | 49 | // with destructuring 50 | function OtherButton({ className, ...props }: ButtonProps) { 51 | return ; 52 | } 53 | ``` 54 | 55 | ## Typing props with default value 56 | 57 | ```tsx 58 | type ButtonProps = { 59 | disabled?: boolean; 60 | className: string; 61 | children: React.ReactNode; 62 | }; 63 | 64 | function Button({ disabled = true, ...props }: ButtonProps) { 65 | return ( 66 | 69 | ); 70 | } 71 | ``` 72 | 73 | ## Typing props with children 74 | 75 | ```tsx 76 | type ButtonProps = { 77 | // accept everything React can render 78 | children: React.ReactNode; 79 | }; 80 | 81 | function Button(props: ButtonProps) { 82 | return ; 83 | } 84 | ``` 85 | 86 | ## Using Native HTML props to React Components 87 | 88 | ### 1. Basic 89 | 90 | ```tsx 91 | import React, { ComponentProps } from "react"; 92 | 93 | //ComponentProps<"button"> : get all type/props from native button element 94 | 95 | function Button(props: ComponentProps<"button">) { 96 | return ; 97 | } 98 | ``` 99 | 100 | ### 2. Combine with your type 101 | 102 | ```tsx 103 | import React, { ComponentProps } from "react"; 104 | 105 | type ButtonProps = ComponentProps<"button"> & { 106 | variant: "primary" | "secondary"; 107 | }; 108 | 109 | function Button(props: ButtonProps) { 110 | return ; 111 | } 112 | ``` 113 | 114 | ### 3. Overriding Native Props 115 | 116 | ```tsx 117 | import React, { ComponentProps } from "react"; 118 | 119 | //remove onChange property from input with Omit and combine with new type 120 | type InputProps = Omit, "onChange"> & { 121 | onChange: (value: string) => void; 122 | }; 123 | 124 | function Input(props: InputProps) { 125 | return ; 126 | } 127 | ``` 128 | 129 | ### 4. Extracting Props from Custom Components 130 | 131 | Useful when author of some external library dont export the type definition 132 | 133 | ```tsx 134 | import { ComponentProps } from "react"; 135 | import { Navbar } from "some-ui-library"; 136 | 137 | type NavBarProps = ComponentProps; 138 | ``` 139 | 140 | ## Typing Event Handlers from native element 141 | 142 | Hover native html props in VSCode, you can copy paste the type definition 143 | 144 | ```tsx 145 | type ButtonProps = { 146 | other?: Boolean; 147 | onClick?: React.MouseEventHandler; 148 | }; 149 | ``` 150 | 151 | ![event handler](event-handler.png "event handler") 152 | 153 | ## useState 154 | 155 | ```tsx 156 | // ❌ Typescript already know `text` type is string 157 | const [text, setText] = useState(""); 158 | // ✅ no need to tell typescript, only work with primitive value 159 | const [text, setText] = useState(""); 160 | ``` 161 | 162 | ```tsx 163 | type Tag = { 164 | id: number; 165 | value: string; 166 | }; 167 | 168 | const [tags, setTags] = useState([]); 169 | ``` 170 | 171 | ```tsx 172 | // data : Data | undefined 173 | const [data, setData] = useState(); 174 | // data : Data | undefined 175 | const [data, setData] = useState(undefined); 176 | // data : Data | null 177 | const [data, setData] = useState(null); 178 | ``` 179 | 180 | ## useCallback 181 | 182 | ```tsx 183 | function App(props: { id: number }) { 184 | const handleClick = useCallback( 185 | //⬇️ add type here 186 | (message: string) => { 187 | console.log("name"); 188 | }, 189 | [props.id] 190 | ); 191 | 192 | return ( 193 |
194 |

{message}

195 | 196 | 197 |
198 | ); 199 | } 200 | ``` 201 | 202 | ## useRef 203 | 204 | ### Basic useRef 205 | 206 | ```tsx 207 | export const Component = () => { 208 | // pass type if it doesn't have initial value 209 | const id1 = useRef(); 210 | // no need to pass type if it have initial value 211 | const id2 = useRef(""); 212 | 213 | useEffect(() => { 214 | id1.current = "Random value!"; 215 | }, []); 216 | 217 | return
; 218 | }; 219 | ``` 220 | 221 | ### useRef with HTML element 222 | 223 | you can hover over the type of ref in the element to check what it accepts in your editor 224 | 225 | ```tsx 226 | export const Component1 = () => { 227 | // add null to initial value 228 | const ref = useRef(null); 229 | 230 | //(property) React.ClassAttributes.ref?: React.LegacyRef | undefined 231 | return