diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index eb21ae9d..6d43425c 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -10,3 +10,39 @@ I thought I should lay out some core principles that we will follow so that this
4. **Add TypeScript Playground Links**: Whenever adding a code example longer than four lines, add a link to the TypeScript Playground with the code. Use the default compiler Playground options.
That's all I've got! Again, really happy you are thinking about helping out, who knows, the person who you might be helping is yourself in future!
+
+## Project structure
+
+- All content is in `/docs`
+ - the `/docs/basic` is compiled into `README.md` to preserve GitHub readability via GitHub action, thanks
+- `/website` consumes the `/docs` content, which is a [Docusaurus 2](https://docusaurus.io/) site, which also has [Algolia search](https://www.algolia.com/) (thanks to both teams for their support!)
+
+The website is deployed to Netlify on swyx's personal account.
+
+To run the docsite locally:
+
+```bash
+yarn # install deps
+## make sure deps are installed in /website too
+cd website && yarn start
+```
+
+example output from successful startup
+
+```
+yarn run v1.22.4
+warning package.json: No license field
+$ docusaurus start
+Starting the development server...
+
+✔ Client
+ Compiled successfully in 9.61s
+
+ℹ 「wds」: Project is running at http://localhost:3000/
+ℹ 「wds」: webpack output is served from /
+ℹ 「wds」: Content not from webpack is served from /Users/wanshawn/Work/react-typescript-cheatsheet/website
+ℹ 「wds」: 404s will fallback to /index.html
+
+✔ Client
+ Compiled successfully in 116.41ms
+```
diff --git a/README.md b/README.md
index eaa5dd55..4f19bd25 100644
--- a/README.md
+++ b/README.md
@@ -25,7 +25,7 @@
-:wave: This repo is maintained by [@swyx](https://twitter.com/swyx), [@ferdaber](https://twitter.com/ferdaber), [@eps1lon](https://twitter.com/sebsilbermann), [@IslamAttrash](https://twitter.com/IslamAttrash), [@jsjoeio](https://twitter.com/jsjoeio) and [@arvindcheenu](https://twitter.com/arvincheenu), we're so happy you want to try out TypeScript with React! If you see anything wrong or missing, please [file an issue](https://github.com/typescript-cheatsheets/react-typescript-cheatsheet/issues/new/choose)! :+1:
+:wave: This repo is maintained by [@swyx](https://twitter.com/swyx), [@ferdaber](https://twitter.com/ferdaber), [@eps1lon](https://twitter.com/sebsilbermann), [@jsjoeio](https://twitter.com/jsjoeio) and [@arvindcheenu](https://twitter.com/arvincheenu), we're so happy you want to try out TypeScript with React! If you see anything wrong or missing, please [file an issue](https://github.com/typescript-cheatsheets/react-typescript-cheatsheet/issues/new/choose)! :+1:
diff --git a/docs/advanced/guides/conditionally-rendering.md b/docs/advanced/guides/conditionally-rendering.md
deleted file mode 100644
index c18bca78..00000000
--- a/docs/advanced/guides/conditionally-rendering.md
+++ /dev/null
@@ -1,54 +0,0 @@
----
-id: conditionally_rendering
-title: Conditionally Rendering Components
----
-
-Use [type guards](https://basarat.gitbooks.io/typescript/docs/types/typeGuard.html#user-defined-type-guards)!
-
-```tsx
-// Button props
-type ButtonProps = React.ButtonHTMLAttributes & {
- href?: undefined;
-};
-
-// Anchor props
-type AnchorProps = React.AnchorHTMLAttributes & {
- href?: string;
-};
-
-// Input/output options
-type Overload = {
- (props: ButtonProps): JSX.Element;
- (props: AnchorProps): JSX.Element;
-};
-
-// Guard to check if href exists in props
-const hasHref = (props: ButtonProps | AnchorProps): props is AnchorProps =>
- "href" in props;
-
-// Component
-const Button: Overload = (props: ButtonProps | AnchorProps) => {
- // anchor render
- if (hasHref(props)) return ;
- // button render
- return ;
-};
-
-// Usage
-function App() {
- return (
- <>
- {/* 😎 All good */}
-
- {/* 😭 Error, `disabled` doesnt exist on anchor element */}
-
- >
- );
-}
-```
-
-[View in the TypeScript Playground](https://www.typescriptlang.org/play/?jsx=2#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wFgAoAekrgCEBXGGCAOzjBzAGcKYBPMEjqNmLAAqcucALyJiMAHQMmrABIAVALIAZAIJMowAEaMkXADwady0QFEANkhBIWMAHxwAZHADeFOHAAFkSYAPwAXHD0LAAmSJjALEgxANwUAL5p5BTUcLosaIHQ7JK8AkL5hdASENwycuiKlUVQVnoGxqYWbc3QDk4u7l6+-kEhEXBcMIYsAOZZmRQ5NACSLGCMlBCMG-C1MMCsPOT8gnAA8gBuSFD2ECgx9X7kAQAUHLVckTasNdwAlJEAFIAZQAGgp+s5XFk3h9uJFelA-lxAXBQRCoYMFlllnAAOL0FBQR7MOCFJBoADWcGAmDG8TgSAAHsAplJEiVPhQ0Ed4IEUFxVCF6u9JN8RL9JHAAD55AotFFo+EcqRIlEyNyjABEwXi2tpbBVuKoNAAwrhIElXDy+cIVCxIlcbncHqKVRKHRq5erJP9NSMXnBcigFcUiLEbqM6XBXgKhSExZ9-v6iDB6FA2OYUL4FHmVelg25YcGaCYHXAI3EoKM0xms+XRLn85JC5RixkTbkAKpcFCzJAUTDRDCHNi6MBgV7+54BOuZ2OjALmLVBgIBHyUABUcEAvBuAOD28vZ7HBZhAII8t5R0kv1+YfmwYMSBzBpNqAPpGeyhqkGvWYN9AiYBFqAAd3AhQzwgWZHAUXkQG1Vd12QuB1DMGBb2XSgHyQlDNx3XdAFo9uBbCgHAoAAGjgAADGI2RQL9kmouAYggMxXCZVkpjgVg4FDKooCZRxoXgK8bzXO8HxY+jGMef832ZRDMPXNCpmU8xsMlFhcKw3D-gWIA)
diff --git a/docs/advanced/guides/extract-props.md b/docs/advanced/guides/extract-props.md
deleted file mode 100644
index d7ef6673..00000000
--- a/docs/advanced/guides/extract-props.md
+++ /dev/null
@@ -1,47 +0,0 @@
----
-id: extract_props
-title: "Props: Extracting Prop Types of a Component"
----
-
-_(Contributed by [@ferdaber](https://github.com/typescript-cheatsheets/react-typescript-cheatsheet/issues/63))_
-
-There are a lot of places where you want to reuse some slices of props because of prop drilling,
-so you can either export the props type as part of the module or extract them (either way works).
-
-The advantage of extracting the prop types is that you won't need to export everything, and a refactor of the source of truth component will propagate to all consuming components.
-
-```ts
-import { ComponentProps, JSXElementConstructor } from "react";
-
-// goes one step further and resolves with propTypes and defaultProps properties
-type ApparentComponentProps<
- C extends keyof JSX.IntrinsicElements | JSXElementConstructor
-> = C extends JSXElementConstructor
- ? JSX.LibraryManagedAttributes
- : ComponentProps;
-```
-
-You can also use them to strongly type custom event handlers if they're not written at the call sites themselves
-(i.e. inlined with the JSX attribute):
-
-```tsx
-// my-inner-component.tsx
-export function MyInnerComponent(props: {
- onSomeEvent(
- event: ComplexEventObj,
- moreArgs: ComplexArgs
- ): SomeWeirdReturnType;
-}) {
- /* ... */
-}
-
-// my-consuming-component.tsx
-export function MyConsumingComponent() {
- // event and moreArgs are contextually typed along with the return value
- const theHandler: Props["onSomeEvent"] = (
- event,
- moreArgs
- ) => {};
- return ;
-}
-```
diff --git a/docs/advanced/guides/generic-components.md b/docs/advanced/guides/generic-components.md
deleted file mode 100644
index c5393db3..00000000
--- a/docs/advanced/guides/generic-components.md
+++ /dev/null
@@ -1,203 +0,0 @@
----
-id: generic_components
-title: Generic Components
----
-
-Just as you can make generic functions and classes in TypeScript, you can also make generic components to take advantage of the type system for reusable type safety. Both Props and State can take advantage of the same generic types, although it probably makes more sense for Props than for State. You can then use the generic type to annotate types of any variables defined inside your function / class scope.
-
-```tsx
-interface Props {
- items: T[];
- renderItem: (item: T) => React.ReactNode;
-}
-function List(props: Props) {
- const { items, renderItem } = props;
- const [state, setState] = React.useState([]); // You can use type T in List function scope.
- return (
-
- );
-}
-```
-
-You can then use the generic components and get nice type safety through type inference:
-
-```tsx
-ReactDOM.render(
- (
-
- {/* Error: Property 'toPrecision' does not exist on type 'string'. */}
- {item.toPrecision(3)}
-
- )}
- />,
- document.body
-);
-```
-
-As of [TS 2.9](#typescript-29), you can also supply the type parameter in your JSX to opt out of type inference:
-
-```tsx
-ReactDOM.render(
-
- items={["a", "b"]} // Error: Type 'string' is not assignable to type 'number'.
- renderItem={(item) =>
{item.toPrecision(3)}
}
- />,
- document.body
-);
-```
-
-You can also use Generics using fat arrow function style:
-
-```tsx
-interface Props {
- items: T[];
- renderItem: (item: T) => React.ReactNode;
-}
-
-// Note the before the function definition.
-// You can't use just `` as it will confuse the TSX parser whether it's a JSX tag or a Generic Declaration.
-// You can also use https://github.com/microsoft/TypeScript/issues/15713#issuecomment-499474386
-const List = (props: Props) => {
- const { items, renderItem } = props;
- const [state, setState] = React.useState([]); // You can use type T in List function scope.
- return (
-
- );
- }
-}
-```
-
-Though you can't use Generic Type Parameters for Static Members:
-
-```tsx
-class List extends React.PureComponent, State> {
- // Static members cannot reference class type parameters.ts(2302)
- static getDerivedStateFromProps(props: Props, state: State) {
- return { items: props.items };
- }
-}
-```
-
-To fix this you need to convert your static function to a type inferred function:
-
-```tsx
-class List extends React.PureComponent, State> {
- static getDerivedStateFromProps(props: Props, state: State) {
- return { items: props.items };
- }
-}
-```
-
-### Generic components with children
-
-`children` is usually not defined as a part of the props type. Unless `children` are explicitly defined as a part of the `props` type, an attempt to use `props.children` in JSX or in the function body will fail:
-
-```tsx
-interface WrapperProps {
- item: T;
- renderItem: (item: T) => React.ReactNode;
-}
-
-/* Property 'children' does not exist on type 'WrapperProps'. */
-const Wrapper = (props: WrapperProps) => {
- return (
-
- );
-};
-
-/*
-Type '{ children: string; item: string; renderItem: (item: string) => string; }' is not assignable to type 'IntrinsicAttributes & WrapperProps'.
- Property 'children' does not exist on type 'IntrinsicAttributes & WrapperProps'.
-*/
-
-const wrapper = (
- item}>
- {test}
-
-);
-```
-
-[View in the TypeScript Playground](https://www.typescriptlang.org/play/?jsx=2#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wFgAoC4AOxiSk3STgHUoUwx6AFHMAZwA8AFQB8cAN4U4cYHRAAuOMIDc0uEWoATegEl5SgBRyki5QEo4AXnHJ0MAHR2MAOQg615GWgAWwADZamkrOjqFuHhQAvhQUAPQAVHC8EFywAJ4EvgFBSNT4cFoQSPxw1BDwSAAewPzwENRwMOlcBGwcaSkCIqL4DnAJcRRoDXWs7Jz01nAicNV02qUSUaKGYHz8Su2TUF1CYpY2kupEMACuUI2G6jKCWsAAbqI3MpLrqfwOmjpQ+qZrGwcJhA5hiXleMgk7wEDmygU0YIhgji9ye6nMniinniCQowhazHwEjgcNy1CUdSgNAA5ipZAY4JSaXTvnoGcYGUzqNTDuIubS4FECrUyhU4Ch+PxgNTqCgAEb+ZgwCBNAkEXS0KnUKVoACCMBgVLlZzopQAZOMOjwNoJ+b0HOouvRmlk-PC8gUiiVRZUamMGqrWvgNYaaDr9aHjaa4Bbtp0bXa+hRBrFyCNtfBTfArHBDLyZqjRAAJJD+fwqrPIwvDUbwADuEzS02u4MEcamwKsACIs12NHkfn8QFYJMDrOJgSsXhIs4iZnF21BnuQMUA)
-
-To work around that, either add `children` to the `WrapperProps` definition (possibly narrowing down its type, as needed):
-
-```tsx
-interface WrapperProps {
- item: T;
- renderItem: (item: T) => React.ReactNode;
- children: string; // The component will only accept a single string child
-}
-
-const Wrapper = (props: WrapperProps) => {
- return (
-
- );
-};
-```
diff --git a/docs/advanced/guides/handling-exceptions.md b/docs/advanced/guides/handling-exceptions.md
deleted file mode 100644
index 03813912..00000000
--- a/docs/advanced/guides/handling-exceptions.md
+++ /dev/null
@@ -1,109 +0,0 @@
----
-id: handling_exceptions
-title: Handling Exceptions
----
-
-You can provide good information when bad things happen.
-
-```ts
-class InvalidDateFormatError extends RangeError {}
-class DateIsInFutureError extends RangeError {}
-
-/**
- * // optional docblock
- * @throws {InvalidDateFormatError} The user entered date incorrectly
- * @throws {DateIsInFutureError} The user entered date in future
- *
- */
-function parse(date: string) {
- if (!isValid(date))
- throw new InvalidDateFormatError("not a valid date format");
- if (isInFuture(date)) throw new DateIsInFutureError("date is in the future");
- // ...
-}
-
-try {
- // call parse(date) somewhere
-} catch (e) {
- if (e instanceof InvalidDateFormatError) {
- console.error("invalid date format", e);
- } else if (e instanceof DateIsInFutureError) {
- console.warn("date is in future", e);
- } else {
- throw e;
- }
-}
-```
-
-[View in TypeScript Playground](https://www.typescriptlang.org/play/?jsx=2#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wFgAoCtAGxQGc64BJAOwDcVrgATAERRhIAYtBACAolBxQ4SAB6CW3RghQsA5kknS4AbwC+VWgzj9BTOqyEBXGNaLboshUiUq1mxzIMUKmaywYwBAscMB0AGqcPAAU3AJIAFxwdDBQwBoAlHoUcHBEdlCh8YJwAPxwadZIcMmYnHRIANwUhpTk-oEwwaHhVrb2SHEJyanpWTnkeWghqXAlSAByEADucAC8cCxIa2ZDmS1TcDMsc2j2RCwwextbO6YJw4KZuXCvBfah51Ku1wkAdJoYAAVUD7OAAPnmCWWK0BSBBYJiB1avnIAHoAFSY3KYuDo9FwCBgbohTjzCBoABG1EpAGtcXAAAIwAAWOBWjF0rA4XD4CREUDEMC8+jgwNZNWsjRkvyQRG40NKGRmPww1AAnoyWezVly9hZ+oUtFJoGKJVKZbIrvKkIqFmFQv5jbjcei-AEgiE4GAUFBGk8kik0hl1NldK9gJg4DEAIThKJ8wOZF5HPJsjl3NY86L8wSC4VeGIAIhYEHgKDgvJ4SpqmFEAmLKKOUZjfRYNmNyeyGdWWYe5ksHYGDlNUBLDvCjsqkrgzsGTcOeQJcH+a9R7TSGsmy8JaE41B9foDC2ydFwO0lRFaxwEaFZMaQ4cj0ZiNQyqTUaCQEGjOb5ewFhIY7PmmxyzBA1BIP88rSCWGTVvaCRzg2MDFgANLIzZ5GKSDUI0YSvu+pwwF+P7RgaQ6doMXigXk0wQVB-wrH6LATshU4ZHOI5IBhWFLnAuH4TUEZgb2azNK8bT6EAA)
-
-Simply throwing an exception is fine, however it would be nice to make TypeScript remind the consumer of your code to handle your exception. We can do that just by returning instead of throwing:
-
-```ts
-function parse(
- date: string
-): Date | InvalidDateFormatError | DateIsInFutureError {
- if (!isValid(date))
- return new InvalidDateFormatError("not a valid date format");
- if (isInFuture(date)) return new DateIsInFutureError("date is in the future");
- // ...
-}
-
-// now consumer *has* to handle the errors
-let result = parse("mydate");
-if (result instanceof InvalidDateFormatError) {
- console.error("invalid date format", result.message);
-} else if (result instanceof DateIsInFutureError) {
- console.warn("date is in future", result.message);
-} else {
- /// use result safely
-}
-
-// alternately you can just handle all errors
-if (result instanceof Error) {
- console.error("error", result);
-} else {
- /// use result safely
-}
-```
-
-You can also describe exceptions with special-purpose data types (don't say monads...) like the `Try`, `Option` (or `Maybe`), and `Either` data types:
-
-```ts
-interface Option {
- flatMap(f: (value: T) => None): None;
- flatMap(f: (value: T) => Option): FormikOption;
- getOrElse(value: T): T;
-}
-class Some implements Option {
- constructor(private value: T) {}
- flatMap(f: (value: T) => None): None;
- flatMap(f: (value: T) => Some): Some;
- flatMap(f: (value: T) => Option): Option {
- return f(this.value);
- }
- getOrElse(): T {
- return this.value;
- }
-}
-class None implements Option {
- flatMap(): None {
- return this;
- }
- getOrElse(value: U): U {
- return value;
- }
-}
-
-// now you can use it like:
-let result = Option(6) // Some
- .flatMap((n) => Option(n * 3)) // Some
- .flatMap((n = new None())) // None
- .getOrElse(7);
-
-// or:
-let result = ask() // Option
- .flatMap(parse) // Option
- .flatMap((d) => new Some(d.toISOString())) // Option
- .getOrElse("error parsing string");
-```
diff --git a/docs/advanced/guides/hocs.md b/docs/advanced/guides/hocs.md
deleted file mode 100644
index 6ae06582..00000000
--- a/docs/advanced/guides/hocs.md
+++ /dev/null
@@ -1,6 +0,0 @@
----
-id: hocs
-title: Higher Order Components (HOCs)
----
-
-**There is now a dedicated [HOC cheatsheet](../../hoc/index.md) you can refer to get some practice on HOCs.**
diff --git a/docs/advanced/guides/omit-attr.md b/docs/advanced/guides/omit-attr.md
deleted file mode 100644
index ebeb9e84..00000000
--- a/docs/advanced/guides/omit-attr.md
+++ /dev/null
@@ -1,47 +0,0 @@
----
-id: omit_attr
-title: Omit attribute from a type
----
-
-Note: [Omit was added as a first class utility in TS 3.5](https://www.typescriptlang.org/docs/handbook/utility-types.html#omittk)! 🎉
-
-Sometimes when intersecting types, we want to define our own version of an attribute. For example, I want my component to have a `label`, but the type I am intersecting with also has a `label` attribute. Here's how to extract that out:
-
-```tsx
-export interface Props {
- label: React.ReactNode; // this will conflict with the InputElement's label
-}
-
-// this comes inbuilt with TS 3.5
-type Omit = Pick>;
-
-// usage
-export const Checkbox = (
- props: Props & Omit, "label">
-) => {
- const { label } = props;
- return (
-
-
- {label}
-
- );
-};
-```
-
-When your component defines multiple props, chances of those conflicts increase. However you can explicitly state that all your fields should be removed from the underlying component using the `keyof` operator:
-
-```tsx
-export interface Props {
- label: React.ReactNode; // conflicts with the InputElement's label
- onChange: (text: string) => void; // conflicts with InputElement's onChange
-}
-
-export const Textbox = (
- props: Props & Omit, keyof Props>
-) => {
- // implement Textbox component ...
-};
-```
diff --git a/docs/advanced/guides/polymorphic-components.md b/docs/advanced/guides/polymorphic-components.md
deleted file mode 100644
index 5a5266d9..00000000
--- a/docs/advanced/guides/polymorphic-components.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-id: polymorphic_components
-title: Polymorphic Components
----
-
-> passing a component to be rendered, e.g. with `as` props
-
-`ElementType` is pretty useful to cover most types that can be passed to createElement e.g.
-
-```tsx
-function PassThrough(props: { as: React.ElementType }) {
- const { as: Component } = props;
-
- return ;
-}
-```
-
-For more info you can refer to these resources:
-
-- https://blog.andrewbran.ch/polymorphic-react-components/
-- https://github.com/kripod/react-polymorphic-box
-
-[Thanks @eps1lon](https://github.com/typescript-cheatsheets/react-typescript-cheatsheet/pull/69) for this
diff --git a/docs/advanced/guides/props-must-pass-both.md b/docs/advanced/guides/props-must-pass-both.md
deleted file mode 100644
index 42f09037..00000000
--- a/docs/advanced/guides/props-must-pass-both.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-id: props_one_other_not_both
-title: "Props: Must Pass Both"
----
-
-```tsx
-type OneOrAnother =
- | (T1 & { [K in keyof T2]?: undefined })
- | (T2 & { [K in keyof T1]?: undefined });
-
-type Props = OneOrAnother<{ a: string; b: string }, {}>;
-
-const a: Props = { a: "a" }; // error
-const b: Props = { b: "b" }; // error
-const ab: Props = { a: "a", b: "b" }; // ok
-```
-
-Thanks [diegohaz](https://twitter.com/kentcdodds/status/1085655423611367426)
diff --git a/docs/advanced/guides/props-one-other-not-both.md b/docs/advanced/guides/props-one-other-not-both.md
deleted file mode 100644
index 47fc823f..00000000
--- a/docs/advanced/guides/props-one-other-not-both.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-id: props_one_other_not_both
-title: "Props: One or the Other but not Both"
----
-
-Use the `in` keyword, function overloading, and union types to make components that take either one or another sets of props, but not both:
-
-```tsx
-type Props1 = { foo: string };
-type Props2 = { bar: string };
-
-function MyComponent(props: Props1 | Props2) {
- if ("foo" in props) {
- // props.bar // error
- return
-);
-```
-
-[View in the TypeScript Playground](https://www.typescriptlang.org/play/?jsx=2#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wFgAoCmATzCTgAUcwBnARjgF44BvOTCBABccFjCjAAdgHM4AXwDcVWvSYRWAJi684AIxRQRYiTPlLK5TAFdJGYBElwAstQDCuSJKSSYACjDMLCJqrBwAPoyBGgCUvBRwcMCYcL4ARAIQqYmOAeossTzxCXAA9CVwuawAdPpQpeVIUDhQRQlEMFZQjgA8ACbAAG4AfDyVLFUZct0l-cPmCXJwSAA2LPSF5MX1FYETgtuNza1w7Z09syNjNQZTM4ND8-IUchRoDmJwAKosKNJI7uAHN4YCJkOgYFUAGKubS+WKcIYpIp9e7HbouAGeYH8QScdKCLIlIZojEeIE+PQGPG1QnEzbFHglABUcHRbjJXgpGTxGSytWpBlSRO2UgGKGWwF6cCZJRe9OmFwo0QUQA)
-
-Further reading: [how to ban passing `{}` if you have a `NoFields` type.](http://www.javiercasas.com/articles/typescript-impossible-states-irrepresentable)
diff --git a/docs/advanced/guides/props-optionally-pass-one.md b/docs/advanced/guides/props-optionally-pass-one.md
deleted file mode 100644
index 86df3a32..00000000
--- a/docs/advanced/guides/props-optionally-pass-one.md
+++ /dev/null
@@ -1,51 +0,0 @@
----
-id: props_optionally_pass_one
-title: "Props: Can Optionally Pass One Only If the Other Is Passed"
----
-
-Say you want a Text component that gets truncated if `truncate` prop is passed but expands to show the full text when `expanded` prop is passed (e.g. when the user clicks the text).
-
-You want to allow `expanded` to be passed only if `truncate` is also passed, because there is no use for `expanded` if the text is not truncated.
-
-You can do this by function overloads:
-
-```tsx
-type CommonProps = {
- children: React.ReactNode;
- miscProps?: any;
-};
-
-type NoTruncateProps = CommonProps & { truncate?: false };
-
-type TruncateProps = CommonProps & { truncate: true; expanded?: boolean };
-
-// Function overloads to accept both prop types NoTruncateProps & TruncateProps
-function Text(props: NoTruncateProps): JSX.Element;
-function Text(props: TruncateProps): JSX.Element;
-function Text(props: CommonProps & { truncate?: boolean; expanded?: boolean }) {
- const { children, truncate, expanded, ...otherProps } = props;
- const classNames = truncate ? ".truncate" : "";
- return (
-
- {children}
-
- );
-}
-```
-
-Using the Text component:
-
-```tsx
-const App: React.FC = () => (
- <>
- {/* these all typecheck */}
- not truncated
- truncated
-
- truncate-able but expanded
-
- {/* TS error: Property 'truncate' is missing in type '{ children: string; expanded: true; }' but required in type '{ truncate: true; expanded?: boolean | undefined; }'. */}
- truncate-able but expanded
- >
-);
-```
diff --git a/docs/advanced/guides/render-props.md b/docs/advanced/guides/render-props.md
deleted file mode 100644
index f9e43c10..00000000
--- a/docs/advanced/guides/render-props.md
+++ /dev/null
@@ -1,31 +0,0 @@
----
-id: render_props
-title: Render Props
----
-
-Sometimes you will want to write a function that can take a React element or a string or something else as a prop. The best Type to use for such a situation is `React.ReactNode` which fits anywhere a normal, well, React Node would fit:
-
-```tsx
-export interface Props {
- label?: React.ReactNode;
- children: React.ReactNode;
-}
-export const Card = (props: Props) => {
- return (
-
- {props.label &&
{props.label}
}
- {props.children}
-
- );
-};
-```
-
-If you are using a function-as-a-child render prop:
-
-```tsx
-export interface Props {
- children: (foo: string) => React.ReactNode;
-}
-```
-
-[Something to add? File an issue](https://github.com/typescript-cheatsheets/react-typescript-cheatsheet/issues/new/choose).
diff --git a/docs/advanced/guides/third-party-libs.md b/docs/advanced/guides/third-party-libs.md
deleted file mode 100644
index f69d6958..00000000
--- a/docs/advanced/guides/third-party-libs.md
+++ /dev/null
@@ -1,6 +0,0 @@
----
-id: third_party_libs
-title: "Props: Third Party Libraries"
----
-
-Sometimes DefinitelyTyped can get it wrong, or isn't quite addressing your use case. You can declare your own file with the same interface name. TypeScript will merge interfaces with the same name.
diff --git a/docs/advanced/guides/type-component-diff-props.md b/docs/advanced/guides/type-component-diff-props.md
deleted file mode 100644
index be812a8f..00000000
--- a/docs/advanced/guides/type-component-diff-props.md
+++ /dev/null
@@ -1,171 +0,0 @@
----
-id: type_component_diff_props
-title: Typing a Component that Accepts Different Props
----
-
-Components, and JSX in general, are analogous to functions. When a component can render differently based on their props, it's similar to how a function can be overloaded to have multiple call signatures. In the same way, you can overload a function component's call signature to list all of its different "versions".
-
-A very common use case for this is to render something as either a button or an anchor, based on if it receives a `href` attribute.
-
-```tsx
-type ButtonProps = JSX.IntrinsicElements["button"];
-type AnchorProps = JSX.IntrinsicElements["a"];
-
-// optionally use a custom type guard
-function isPropsForAnchorElement(
- props: ButtonProps | AnchorProps
-): props is AnchorProps {
- return "href" in props;
-}
-
-function Clickable(props: ButtonProps | AnchorProps) {
- if (isPropsForAnchorElement(props)) {
- return ;
- } else {
- return ;
- }
-}
-```
-
-They don't even need to be completely different props, as long as they have at least one difference in properties:
-
-```tsx
-type LinkProps = Omit & { to?: string };
-
-function RouterLink(props: LinkProps | AnchorProps) {
- if ("href" in props) {
- return ;
- } else {
- return ;
- }
-}
-```
-
-
- Approach: Generic Components
-
-Here is an example solution, see the further discussion for other solutions. _thanks to [@jpavon](https://github.com/typescript-cheatsheets/react-typescript-cheatsheet/issues/12#issuecomment-394440577)_
-
-```tsx
-interface LinkProps {}
-type AnchorProps = React.AnchorHTMLAttributes;
-type RouterLinkProps = Omit;
-
-const Link = (
- props: LinkProps & T extends RouterLinkProps ? RouterLinkProps : AnchorProps
-) => {
- if ((props as RouterLinkProps).to) {
- return ;
- } else {
- return ;
- }
-};
-
- to="/">My link; // ok
- href="/">My link; // ok
- to="/" href="/">
- My link
-; // error
-```
-
-
-
-
- Approach: Composition
-
-If you want to conditionally render a component, sometimes is better to use [React's composition model](https://reactjs.org/docs/composition-vs-inheritance.html) to have simpler components and better to understand typings:
-
-```tsx
-type AnchorProps = React.AnchorHTMLAttributes;
-type RouterLinkProps = Omit;
-
-interface Button {
- as: React.ComponentClass | "a";
-}
-
-const Button: React.FunctionComponent
-
-You may also want to use Discriminated Unions, please check out [Expressive React Component APIs with Discriminated Unions](https://blog.andrewbran.ch/expressive-react-component-apis-with-discriminated-unions/).
-
-Here is a brief intuition for **Discriminated Union Types**:
-
-```ts
-type UserTextEvent = {
- type: "TextEvent";
- value: string;
- target: HTMLInputElement;
-};
-type UserMouseEvent = {
- type: "MouseEvent";
- value: [number, number];
- target: HTMLElement;
-};
-type UserEvent = UserTextEvent | UserMouseEvent;
-function handle(event: UserEvent) {
- if (event.type === "TextEvent") {
- event.value; // string
- event.target; // HTMLInputElement
- return;
- }
- event.value; // [number, number]
- event.target; // HTMLElement
-}
-```
-
-
-
- Take care: TypeScript does not narrow the type of a Discriminated Union on the basis of typeof checks. The type guard has to be on the value of a key and not it's type.
-
-
-```ts
-type UserTextEvent = { value: string; target: HTMLInputElement };
-type UserMouseEvent = { value: [number, number]; target: HTMLElement };
-type UserEvent = UserTextEvent | UserMouseEvent;
-function handle(event: UserEvent) {
- if (typeof event.value === "string") {
- event.value; // string
- event.target; // HTMLInputElement | HTMLElement (!!!!)
- return;
- }
- event.value; // [number, number]
- event.target; // HTMLInputElement | HTMLElement (!!!!)
-}
-```
-
-The above example does not work as we are not checking the value of `event.value` but only it's type. Read more about it [microsoft/TypeScript#30506 (comment)](https://github.com/microsoft/TypeScript/issues/30506#issuecomment-474858198)
-
-
-
-To streamline this you may also combine this with the concept of **User-Defined Type Guards**:
-
-```ts
-function isString(a: unknown): a is string {
- return typeof a === "string";
-}
-```
-
-[Read more about User-Defined Type Guards in the Handbook](https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards).
diff --git a/docs/advanced/guides/type-zoo.md b/docs/advanced/guides/type-zoo.md
deleted file mode 100644
index eb136c59..00000000
--- a/docs/advanced/guides/type-zoo.md
+++ /dev/null
@@ -1,6 +0,0 @@
----
-id: type_zoo
-title: Type Zoo
----
-
-As you can see from the Omit example above, you can write significant logic in your types as well. [type-zoo](https://github.com/pelotom/type-zoo) is a nice toolkit of operators you may wish to check out (includes Omit), as well as [utility-types](https://github.com/piotrwitek/utility-types) (especially for those migrating from Flow).
diff --git a/docs/advanced/patterns_by_usecase.md b/docs/advanced/patterns_by_usecase.md
new file mode 100644
index 00000000..2a2b59b5
--- /dev/null
+++ b/docs/advanced/patterns_by_usecase.md
@@ -0,0 +1,868 @@
+---
+id: patterns_by_usecase
+title: "Useful Patterns by Use Case"
+sidebar_label: Useful Patterns by Use Case
+---
+
+## Wrapping/Mirroring
+
+### Wrapping/Mirroring a HTML Element
+
+Usecase: you want to make a `` that takes all the normal props of `` and does extra stuff.
+
+Strategy: extend `React.HTMLProps`
+
+Example:
+
+```tsx
+export interface ButtonProps extends React.HTMLProps {
+ specialProp: string;
+ type: "button" | "submit" | "reset"; // flaw of React.HTMLProps
+}
+export function Button(props: ButtonProps) {
+ const { specialProp, ...rest } = props;
+ // do something with specialProp
+ return ;
+}
+```
+
+## Wrapping/Mirroring a Component
+
+Usecase: same as above, but for a React Component you don't have access to
+
+```tsx
+const Box = (props: React.CSSProperties) => ;
+
+const Card = ({
+ title,
+ children,
+ ...props
+}: { title: string } & $ElementProps) => (
+
+ {title}: {children}
+
+);
+```
+
+Strategy: extract a component's props by inferring them
+
+Example:
+
+```tsx
+// ReactUtilityTypes.d.ts
+declare type $ElementProps = T extends React.ComponentType
+ ? Props extends object
+ ? Props
+ : never
+ : never;
+```
+
+Advanced Example:
+
+```tsx
+import * as Recompose from "recompose";
+export const defaultProps = <
+ C extends React.ComponentType,
+ D extends Partial<$ElementProps>
+>(
+ defaults: D,
+ Component: C
+): React.ComponentType<$ElementProps & Partial> =>
+ Recompose.defaultProps(defaults)(Component);
+```
+
+_thanks [dmisdm](https://github.com/typescript-cheatsheets/react/issues/23)_
+
+\*TODO: check how this conflicts/merges/duplicates with the Troubleshooting Handbook "Types I need weren't Exported" advice
+
+## Polymorphic Components
+
+> "Polymorphic Components" = passing a component to be rendered, e.g. with `as` props
+
+`ElementType` is pretty useful to cover most types that can be passed to createElement e.g.
+
+```tsx
+function PassThrough(props: { as: React.ElementType }) {
+ const { as: Component } = props;
+
+ return ;
+}
+```
+
+For more info you can refer to these resources:
+
+- https://blog.andrewbran.ch/polymorphic-react-components/
+- https://github.com/kripod/react-polymorphic-box
+
+[Thanks @eps1lon](https://github.com/typescript-cheatsheets/react-typescript-cheatsheet/pull/69) for this!
+
+## Generic Components
+
+Just as you can make generic functions and classes in TypeScript, you can also make generic components to take advantage of the type system for reusable type safety. Both Props and State can take advantage of the same generic types, although it probably makes more sense for Props than for State. You can then use the generic type to annotate types of any variables defined inside your function / class scope.
+
+```tsx
+interface Props {
+ items: T[];
+ renderItem: (item: T) => React.ReactNode;
+}
+function List(props: Props) {
+ const { items, renderItem } = props;
+ const [state, setState] = React.useState([]); // You can use type T in List function scope.
+ return (
+
+ );
+}
+```
+
+You can then use the generic components and get nice type safety through type inference:
+
+```tsx
+ReactDOM.render(
+ (
+
+ {/* Error: Property 'toPrecision' does not exist on type 'string'. */}
+ {item.toPrecision(3)}
+
+ )}
+ />,
+ document.body
+);
+```
+
+As of [TS 2.9](#typescript-29), you can also supply the type parameter in your JSX to opt out of type inference:
+
+```tsx
+ReactDOM.render(
+
+ items={["a", "b"]} // Error: Type 'string' is not assignable to type 'number'.
+ renderItem={(item) =>
{item.toPrecision(3)}
}
+ />,
+ document.body
+);
+```
+
+You can also use Generics using fat arrow function style:
+
+```tsx
+interface Props {
+ items: T[];
+ renderItem: (item: T) => React.ReactNode;
+}
+
+// Note the before the function definition.
+// You can't use just `` as it will confuse the TSX parser whether it's a JSX tag or a Generic Declaration.
+// You can also use https://github.com/microsoft/TypeScript/issues/15713#issuecomment-499474386
+const List = (props: Props) => {
+ const { items, renderItem } = props;
+ const [state, setState] = React.useState([]); // You can use type T in List function scope.
+ return (
+
+ );
+ }
+}
+```
+
+Though you can't use Generic Type Parameters for Static Members:
+
+```tsx
+class List extends React.PureComponent, State> {
+ // Static members cannot reference class type parameters.ts(2302)
+ static getDerivedStateFromProps(props: Props, state: State) {
+ return { items: props.items };
+ }
+}
+```
+
+To fix this you need to convert your static function to a type inferred function:
+
+```tsx
+class List extends React.PureComponent, State> {
+ static getDerivedStateFromProps(props: Props, state: State) {
+ return { items: props.items };
+ }
+}
+```
+
+### Generic components with children
+
+`children` is usually not defined as a part of the props type. Unless `children` are explicitly defined as a part of the `props` type, an attempt to use `props.children` in JSX or in the function body will fail:
+
+```tsx
+interface WrapperProps {
+ item: T;
+ renderItem: (item: T) => React.ReactNode;
+}
+
+/* Property 'children' does not exist on type 'WrapperProps'. */
+const Wrapper = (props: WrapperProps) => {
+ return (
+
+ );
+};
+
+/*
+Type '{ children: string; item: string; renderItem: (item: string) => string; }' is not assignable to type 'IntrinsicAttributes & WrapperProps'.
+ Property 'children' does not exist on type 'IntrinsicAttributes & WrapperProps'.
+*/
+
+const wrapper = (
+ item}>
+ {test}
+
+);
+```
+
+[View in the TypeScript Playground](https://www.typescriptlang.org/play/?jsx=2#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wFgAoC4AOxiSk3STgHUoUwx6AFHMAZwA8AFQB8cAN4U4cYHRAAuOMIDc0uEWoATegEl5SgBRyki5QEo4AXnHJ0MAHR2MAOQg615GWgAWwADZamkrOjqFuHhQAvhQUAPQAVHC8EFywAJ4EvgFBSNT4cFoQSPxw1BDwSAAewPzwENRwMOlcBGwcaSkCIqL4DnAJcRRoDXWs7Jz01nAicNV02qUSUaKGYHz8Su2TUF1CYpY2kupEMACuUI2G6jKCWsAAbqI3MpLrqfwOmjpQ+qZrGwcJhA5hiXleMgk7wEDmygU0YIhgji9ye6nMniinniCQowhazHwEjgcNy1CUdSgNAA5ipZAY4JSaXTvnoGcYGUzqNTDuIubS4FECrUyhU4Ch+PxgNTqCgAEb+ZgwCBNAkEXS0KnUKVoACCMBgVLlZzopQAZOMOjwNoJ+b0HOouvRmlk-PC8gUiiVRZUamMGqrWvgNYaaDr9aHjaa4Bbtp0bXa+hRBrFyCNtfBTfArHBDLyZqjRAAJJD+fwqrPIwvDUbwADuEzS02u4MEcamwKsACIs12NHkfn8QFYJMDrOJgSsXhIs4iZnF21BnuQMUA)
+
+To work around that, either add `children` to the `WrapperProps` definition (possibly narrowing down its type, as needed):
+
+```tsx
+interface WrapperProps {
+ item: T;
+ renderItem: (item: T) => React.ReactNode;
+ children: string; // The component will only accept a single string child
+}
+
+const Wrapper = (props: WrapperProps) => {
+ return (
+
+ );
+};
+```
+
+## Typing Children
+
+Some API designs require some restriction on `children` passed to a parent component. It is common to want to enforce these in types, but you should be aware of limitations to this ability.
+
+### What You CAN Do
+
+You can type the **structure** of your children: just one child, or a tuple of children.
+
+The following are valid:
+
+```ts
+type OneChild = React.ReactElement;
+type TwoChildren = [React.ReactElement, React.ReactElement];
+type ArrayOfProps = SomeProp[];
+type NumbersChildren = number[];
+type TwoNumbersChildren = [number, number];
+```
+
+### What You CANNOT Do
+
+The thing you cannot do is **specify which components** the children are, e.g. If you want to express the fact that "React Router `` can only have `` as children, nothing else is allowed" in TypeScript.
+
+This is because when you write a JSX expression (const foo = ), the resultant type is blackboxed into a generic JSX.Element type. (_[thanks @ferdaber](https://github.com/typescript-cheatsheets/react/issues/271)_)
+
+## Type Narrowing based on Props
+
+What you want:
+
+```tsx
+// Usage
+function App() {
+ return (
+ <>
+ {/* 😎 All good */}
+
+ Test
+
+ {/* 😭 Error, `disabled` doesnt exist on anchor element */}
+
+ Test
+
+ >
+ );
+}
+```
+
+How to implement: Use [type guards](https://basarat.gitbooks.io/typescript/docs/types/typeGuard.html#user-defined-type-guards)!
+
+```tsx
+// Button props
+type ButtonProps = React.ButtonHTMLAttributes & {
+ href?: undefined;
+};
+
+// Anchor props
+type AnchorProps = React.AnchorHTMLAttributes & {
+ href?: string;
+};
+
+// Input/output options
+type Overload = {
+ (props: ButtonProps): JSX.Element;
+ (props: AnchorProps): JSX.Element;
+};
+
+// Guard to check if href exists in props
+const hasHref = (props: ButtonProps | AnchorProps): props is AnchorProps =>
+ "href" in props;
+
+// Component
+const Button: Overload = (props: ButtonProps | AnchorProps) => {
+ // anchor render
+ if (hasHref(props)) return ;
+ // button render
+ return ;
+};
+```
+
+[View in the TypeScript Playground](https://www.typescriptlang.org/play/?jsx=2#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wFgAoAekrgCEBXGGCAOzjBzAGcKYBPMEjqNmLAAqcucALyJiMAHQMmrABIAVALIAZAIJMowAEaMkXADwady0QFEANkhBIWMAHxwAZHADeFOHAAFkSYAPwAXHD0LAAmSJjALEgxANwUAL5p5BTUcLosaIHQ7JK8AkL5hdASENwycuiKlUVQVnoGxqYWbc3QDk4u7l6+-kEhEXBcMIYsAOZZmRQ5NACSLGCMlBCMG-C1MMCsPOT8gnAA8gBuSFD2ECgx9X7kAQAUHLVckTasNdwAlJEAFIAZQAGgp+s5XFk3h9uJFelA-lxAXBQRCoYMFlllnAAOL0FBQR7MOCFJBoADWcGAmDG8TgSAAHsAplJEiVPhQ0Ed4IEUFxVCF6u9JN8RL9JHAAD55AotFFo+EcqRIlEyNyjABEwXi2tpbBVuKoNAAwrhIElXDy+cIVCxIlcbncHqKVRKHRq5erJP9NSMXnBcigFcUiLEbqM6XBXgKhSExZ9-v6iDB6FA2OYUL4FHmVelg25YcGaCYHXAI3EoKM0xms+XRLn85JC5RixkTbkAKpcFCzJAUTDRDCHNi6MBgV7+54BOuZ2OjALmLVBgIBHyUABUcEAvBuAOD28vZ7HBZhAII8t5R0kv1+YfmwYMSBzBpNqAPpGeyhqkGvWYN9AiYBFqAAd3AhQzwgWZHAUXkQG1Vd12QuB1DMGBb2XSgHyQlDNx3XdAFo9uBbCgHAoAAGjgAADGI2RQL9kmouAYggMxXCZVkpjgVg4FDKooCZRxoXgK8bzXO8HxY+jGMef832ZRDMPXNCpmU8xsMlFhcKw3D-gWIA)
+
+Components, and JSX in general, are analogous to functions. When a component can render differently based on their props, it's similar to how a function can be overloaded to have multiple call signatures. In the same way, you can overload a function component's call signature to list all of its different "versions".
+
+A very common use case for this is to render something as either a button or an anchor, based on if it receives a `href` attribute.
+
+```tsx
+type ButtonProps = JSX.IntrinsicElements["button"];
+type AnchorProps = JSX.IntrinsicElements["a"];
+
+// optionally use a custom type guard
+function isPropsForAnchorElement(
+ props: ButtonProps | AnchorProps
+): props is AnchorProps {
+ return "href" in props;
+}
+
+function Clickable(props: ButtonProps | AnchorProps) {
+ if (isPropsForAnchorElement(props)) {
+ return ;
+ } else {
+ return ;
+ }
+}
+```
+
+They don't even need to be completely different props, as long as they have at least one difference in properties:
+
+```tsx
+type LinkProps = Omit & { to?: string };
+
+function RouterLink(props: LinkProps | AnchorProps) {
+ if ("href" in props) {
+ return ;
+ } else {
+ return ;
+ }
+}
+```
+
+
+ Approach: Generic Components
+
+Here is an example solution, see the further discussion for other solutions. _thanks to [@jpavon](https://github.com/typescript-cheatsheets/react-typescript-cheatsheet/issues/12#issuecomment-394440577)_
+
+```tsx
+interface LinkProps {}
+type AnchorProps = React.AnchorHTMLAttributes;
+type RouterLinkProps = Omit;
+
+const Link = (
+ props: LinkProps & T extends RouterLinkProps ? RouterLinkProps : AnchorProps
+) => {
+ if ((props as RouterLinkProps).to) {
+ return ;
+ } else {
+ return ;
+ }
+};
+
+ to="/">My link; // ok
+ href="/">My link; // ok
+ to="/" href="/">
+ My link
+; // error
+```
+
+
+
+
+ Approach: Composition
+
+If you want to conditionally render a component, sometimes is better to use [React's composition model](https://reactjs.org/docs/composition-vs-inheritance.html) to have simpler components and better to understand typings:
+
+```tsx
+type AnchorProps = React.AnchorHTMLAttributes;
+type RouterLinkProps = Omit;
+
+interface Button {
+ as: React.ComponentClass | "a";
+}
+
+const Button: React.FunctionComponent = (props) => {
+ const { as: Component, children, ...rest } = props;
+ return (
+
+ {children}
+
+ );
+};
+
+const AnchorButton: React.FunctionComponent = (props) => (
+
+);
+
+const LinkButton: React.FunctionComponent = (props) => (
+
+);
+
+Login;
+Login;
+
+ Login
+; // Error: Property 'to' does not exist on type...
+```
+
+
+
+You may also want to use Discriminated Unions, please check out [Expressive React Component APIs with Discriminated Unions](https://blog.andrewbran.ch/expressive-react-component-apis-with-discriminated-unions/).
+
+Here is a brief intuition for **Discriminated Union Types**:
+
+```ts
+type UserTextEvent = {
+ type: "TextEvent";
+ value: string;
+ target: HTMLInputElement;
+};
+type UserMouseEvent = {
+ type: "MouseEvent";
+ value: [number, number];
+ target: HTMLElement;
+};
+type UserEvent = UserTextEvent | UserMouseEvent;
+function handle(event: UserEvent) {
+ if (event.type === "TextEvent") {
+ event.value; // string
+ event.target; // HTMLInputElement
+ return;
+ }
+ event.value; // [number, number]
+ event.target; // HTMLElement
+}
+```
+
+
+
+ Take care: TypeScript does not narrow the type of a Discriminated Union on the basis of typeof checks. The type guard has to be on the value of a key and not it's type.
+
+
+```ts
+type UserTextEvent = { value: string; target: HTMLInputElement };
+type UserMouseEvent = { value: [number, number]; target: HTMLElement };
+type UserEvent = UserTextEvent | UserMouseEvent;
+function handle(event: UserEvent) {
+ if (typeof event.value === "string") {
+ event.value; // string
+ event.target; // HTMLInputElement | HTMLElement (!!!!)
+ return;
+ }
+ event.value; // [number, number]
+ event.target; // HTMLInputElement | HTMLElement (!!!!)
+}
+```
+
+The above example does not work as we are not checking the value of `event.value` but only it's type. Read more about it [microsoft/TypeScript#30506 (comment)](https://github.com/microsoft/TypeScript/issues/30506#issuecomment-474858198)
+
+
+
+To streamline this you may also combine this with the concept of **User-Defined Type Guards**:
+
+```ts
+function isString(a: unknown): a is string {
+ return typeof a === "string";
+}
+```
+
+[Read more about User-Defined Type Guards in the Handbook](https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards).
+
+## Props: One or the Other but not Both
+
+Use the `in` keyword, function overloading, and union types to make components that take either one or another sets of props, but not both:
+
+```tsx
+type Props1 = { foo: string };
+type Props2 = { bar: string };
+
+function MyComponent(props: Props1 | Props2) {
+ if ("foo" in props) {
+ // props.bar // error
+ return
+);
+```
+
+[View in the TypeScript Playground](https://www.typescriptlang.org/play/?jsx=2#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wFgAoCmATzCTgAUcwBnARjgF44BvOTCBABccFjCjAAdgHM4AXwDcVWvSYRWAJi684AIxRQRYiTPlLK5TAFdJGYBElwAstQDCuSJKSSYACjDMLCJqrBwAPoyBGgCUvBRwcMCYcL4ARAIQqYmOAeossTzxCXAA9CVwuawAdPpQpeVIUDhQRQlEMFZQjgA8ACbAAG4AfDyVLFUZct0l-cPmCXJwSAA2LPSF5MX1FYETgtuNza1w7Z09syNjNQZTM4ND8-IUchRoDmJwAKosKNJI7uAHN4YCJkOgYFUAGKubS+WKcIYpIp9e7HbouAGeYH8QScdKCLIlIZojEeIE+PQGPG1QnEzbFHglABUcHRbjJXgpGTxGSytWpBlSRO2UgGKGWwF6cCZJRe9OmFwo0QUQA)
+
+Further reading: [how to ban passing `{}` if you have a `NoFields` type.](http://www.javiercasas.com/articles/typescript-impossible-states-irrepresentable)
+
+## Props: Must Pass Both
+
+```tsx
+type OneOrAnother =
+ | (T1 & { [K in keyof T2]?: undefined })
+ | (T2 & { [K in keyof T1]?: undefined });
+
+type Props = OneOrAnother<{ a: string; b: string }, {}>;
+
+const a: Props = { a: "a" }; // error
+const b: Props = { b: "b" }; // error
+const ab: Props = { a: "a", b: "b" }; // ok
+```
+
+Thanks [diegohaz](https://twitter.com/kentcdodds/status/1085655423611367426)
+
+## Props: Pass One ONLY IF the Other Is Passed
+
+Say you want a Text component that gets truncated if `truncate` prop is passed but expands to show the full text when `expanded` prop is passed (e.g. when the user clicks the text).
+
+You want to allow `expanded` to be passed only if `truncate` is also passed, because there is no use for `expanded` if the text is not truncated.
+
+Usage example:
+
+```tsx
+const App: React.FC = () => (
+ <>
+ {/* these all typecheck */}
+ not truncated
+ truncated
+
+ truncate-able but expanded
+
+ {/* TS error: Property 'truncate' is missing in type '{ children: string; expanded: true; }' but required in type '{ truncate: true; expanded?: boolean | undefined; }'. */}
+ truncate-able but expanded
+ >
+);
+```
+
+You can implement this by function overloads:
+
+```tsx
+type CommonProps = {
+ children: React.ReactNode;
+ miscProps?: any;
+};
+
+type NoTruncateProps = CommonProps & { truncate?: false };
+
+type TruncateProps = CommonProps & { truncate: true; expanded?: boolean };
+
+// Function overloads to accept both prop types NoTruncateProps & TruncateProps
+function Text(props: NoTruncateProps): JSX.Element;
+function Text(props: TruncateProps): JSX.Element;
+function Text(props: CommonProps & { truncate?: boolean; expanded?: boolean }) {
+ const { children, truncate, expanded, ...otherProps } = props;
+ const classNames = truncate ? ".truncate" : "";
+ return (
+
+ {children}
+
+ );
+}
+```
+
+## Props: Omit prop from a type
+
+Note: [Omit was added as a first class utility in TS 3.5](https://www.typescriptlang.org/docs/handbook/utility-types.html#omittk)! 🎉
+
+Sometimes when intersecting types, we want to define our own version of a prop. For example, I want my component to have a `label`, but the type I am intersecting with also has a `label` prop. Here's how to extract that out:
+
+```tsx
+export interface Props {
+ label: React.ReactNode; // this will conflict with the InputElement's label
+}
+
+// this comes inbuilt with TS 3.5
+type Omit = Pick>;
+
+// usage
+export const Checkbox = (
+ props: Props & Omit, "label">
+) => {
+ const { label } = props;
+ return (
+
+
+ {label}
+
+ );
+};
+```
+
+When your component defines multiple props, chances of those conflicts increase. However you can explicitly state that all your fields should be removed from the underlying component using the `keyof` operator:
+
+```tsx
+export interface Props {
+ label: React.ReactNode; // conflicts with the InputElement's label
+ onChange: (text: string) => void; // conflicts with InputElement's onChange
+}
+
+export const Textbox = (
+ props: Props & Omit, keyof Props>
+) => {
+ // implement Textbox component ...
+};
+```
+
+As you can see from the Omit example above, you can write significant logic in your types as well. [type-zoo](https://github.com/pelotom/type-zoo) is a nice toolkit of operators you may wish to check out (includes Omit), as well as [utility-types](https://github.com/piotrwitek/utility-types) (especially for those migrating from Flow).
+
+## Props: Extracting Prop Types of a Component
+
+There are a lot of places where you want to reuse some slices of props because of prop drilling,
+so you can either export the props type as part of the module or extract them (either way works).
+
+The advantage of extracting the prop types is that you won't need to export everything, and a refactor of the source of truth component will propagate to all consuming components.
+
+```ts
+import { ComponentProps, JSXElementConstructor } from "react";
+
+// goes one step further and resolves with propTypes and defaultProps properties
+type ApparentComponentProps<
+ C extends keyof JSX.IntrinsicElements | JSXElementConstructor
+> = C extends JSXElementConstructor
+ ? JSX.LibraryManagedAttributes
+ : ComponentProps;
+```
+
+You can also use them to strongly type custom event handlers if they're not written at the call sites themselves
+(i.e. inlined with the JSX attribute):
+
+```tsx
+// my-inner-component.tsx
+export function MyInnerComponent(props: {
+ onSomeEvent(
+ event: ComplexEventObj,
+ moreArgs: ComplexArgs
+ ): SomeWeirdReturnType;
+}) {
+ /* ... */
+}
+
+// my-consuming-component.tsx
+export function MyConsumingComponent() {
+ // event and moreArgs are contextually typed along with the return value
+ const theHandler: Props["onSomeEvent"] = (
+ event,
+ moreArgs
+ ) => {};
+ return ;
+}
+```
+
+## Props: Render Props
+
+> Advice: Where possible, you should try to use Hooks instead of Render Props. We include this merely for completeness.
+
+Sometimes you will want to write a function that can take a React element or a string or something else as a prop. The best Type to use for such a situation is `React.ReactNode` which fits anywhere a normal, well, React Node would fit:
+
+```tsx
+export interface Props {
+ label?: React.ReactNode;
+ children: React.ReactNode;
+}
+export const Card = (props: Props) => {
+ return (
+
+ {props.label &&
{props.label}
}
+ {props.children}
+
+ );
+};
+```
+
+If you are using a function-as-a-child render prop:
+
+```tsx
+export interface Props {
+ children: (foo: string) => React.ReactNode;
+}
+```
+
+[Something to add? File an issue](https://github.com/typescript-cheatsheets/react-typescript-cheatsheet/issues/new/choose).
+
+## Handling Exceptions
+
+You can provide good information when bad things happen.
+
+```ts
+class InvalidDateFormatError extends RangeError {}
+class DateIsInFutureError extends RangeError {}
+
+/**
+ * // optional docblock
+ * @throws {InvalidDateFormatError} The user entered date incorrectly
+ * @throws {DateIsInFutureError} The user entered date in future
+ *
+ */
+function parse(date: string) {
+ if (!isValid(date))
+ throw new InvalidDateFormatError("not a valid date format");
+ if (isInFuture(date)) throw new DateIsInFutureError("date is in the future");
+ // ...
+}
+
+try {
+ // call parse(date) somewhere
+} catch (e) {
+ if (e instanceof InvalidDateFormatError) {
+ console.error("invalid date format", e);
+ } else if (e instanceof DateIsInFutureError) {
+ console.warn("date is in future", e);
+ } else {
+ throw e;
+ }
+}
+```
+
+[View in TypeScript Playground](https://www.typescriptlang.org/play/?jsx=2#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wFgAoCtAGxQGc64BJAOwDcVrgATAERRhIAYtBACAolBxQ4SAB6CW3RghQsA5kknS4AbwC+VWgzj9BTOqyEBXGNaLboshUiUq1mxzIMUKmaywYwBAscMB0AGqcPAAU3AJIAFxwdDBQwBoAlHoUcHBEdlCh8YJwAPxwadZIcMmYnHRIANwUhpTk-oEwwaHhVrb2SHEJyanpWTnkeWghqXAlSAByEADucAC8cCxIa2ZDmS1TcDMsc2j2RCwwextbO6YJw4KZuXCvBfah51Ku1wkAdJoYAAVUD7OAAPnmCWWK0BSBBYJiB1avnIAHoAFSY3KYuDo9FwCBgbohTjzCBoABG1EpAGtcXAAAIwAAWOBWjF0rA4XD4CREUDEMC8+jgwNZNWsjRkvyQRG40NKGRmPww1AAnoyWezVly9hZ+oUtFJoGKJVKZbIrvKkIqFmFQv5jbjcei-AEgiE4GAUFBGk8kik0hl1NldK9gJg4DEAIThKJ8wOZF5HPJsjl3NY86L8wSC4VeGIAIhYEHgKDgvJ4SpqmFEAmLKKOUZjfRYNmNyeyGdWWYe5ksHYGDlNUBLDvCjsqkrgzsGTcOeQJcH+a9R7TSGsmy8JaE41B9foDC2ydFwO0lRFaxwEaFZMaQ4cj0ZiNQyqTUaCQEGjOb5ewFhIY7PmmxyzBA1BIP88rSCWGTVvaCRzg2MDFgANLIzZ5GKSDUI0YSvu+pwwF+P7RgaQ6doMXigXk0wQVB-wrH6LATshU4ZHOI5IBhWFLnAuH4TUEZgb2azNK8bT6EAA)
+
+Simply throwing an exception is fine, however it would be nice to make TypeScript remind the consumer of your code to handle your exception. We can do that just by returning instead of throwing:
+
+```ts
+function parse(
+ date: string
+): Date | InvalidDateFormatError | DateIsInFutureError {
+ if (!isValid(date))
+ return new InvalidDateFormatError("not a valid date format");
+ if (isInFuture(date)) return new DateIsInFutureError("date is in the future");
+ // ...
+}
+
+// now consumer *has* to handle the errors
+let result = parse("mydate");
+if (result instanceof InvalidDateFormatError) {
+ console.error("invalid date format", result.message);
+} else if (result instanceof DateIsInFutureError) {
+ console.warn("date is in future", result.message);
+} else {
+ /// use result safely
+}
+
+// alternately you can just handle all errors
+if (result instanceof Error) {
+ console.error("error", result);
+} else {
+ /// use result safely
+}
+```
+
+You can also describe exceptions with special-purpose data types (don't say monads...) like the `Try`, `Option` (or `Maybe`), and `Either` data types:
+
+```ts
+interface Option {
+ flatMap(f: (value: T) => None): None;
+ flatMap(f: (value: T) => Option): FormikOption;
+ getOrElse(value: T): T;
+}
+class Some implements Option {
+ constructor(private value: T) {}
+ flatMap(f: (value: T) => None): None;
+ flatMap(f: (value: T) => Some): Some;
+ flatMap(f: (value: T) => Option): Option {
+ return f(this.value);
+ }
+ getOrElse(): T {
+ return this.value;
+ }
+}
+class None implements Option {
+ flatMap(): None {
+ return this;
+ }
+ getOrElse(value: U): U {
+ return value;
+ }
+}
+
+// now you can use it like:
+let result = Option(6) // Some
+ .flatMap((n) => Option(n * 3)) // Some
+ .flatMap((n = new None())) // None
+ .getOrElse(7);
+
+// or:
+let result = ask() // Option
+ .flatMap(parse) // Option
+ .flatMap((d) => new Some(d.toISOString())) // Option
+ .getOrElse("error parsing string");
+```
diff --git a/docs/advanced/patterns.md b/docs/advanced/patterns_by_version.md
similarity index 93%
rename from docs/advanced/patterns.md
rename to docs/advanced/patterns_by_version.md
index ca8817fd..0cedc337 100644
--- a/docs/advanced/patterns.md
+++ b/docs/advanced/patterns_by_version.md
@@ -1,6 +1,6 @@
---
-id: patterns
-title: "Section 2: Useful Patterns by TypeScript Version"
+id: patterns_by_version
+title: "Useful Patterns by TypeScript Version"
sidebar_label: Useful Patterns by TypeScript Version
---
@@ -382,7 +382,7 @@ handy for JSDoc users - `@public, @private, @protected, @readonly`
## TypeScript 3.9
-[[Release Candidate](https://devblogs.microsoft.com/typescript/announcing-typescript-3-9-rc/)]
+[[Release Notes](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-9.html) | [Blog Post](https://devblogs.microsoft.com/typescript/announcing-typescript-3-9/)]
1. (minor feature) New `ts-expect-error` directive.
@@ -418,14 +418,36 @@ You can [convert these in bulk](https://github.com/microsoft/TypeScript/pull/374
## TypeScript 4.0
-[[Release Candidate](https://devblogs.microsoft.com/typescript/announcing-typescript-4-0-beta/#variadic-tuple-types)]
+[[Release Notes](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-0.html) | [Blog Post](https://devblogs.microsoft.com/typescript/announcing-typescript-4-0/)]
- [Variadic Tuple Types](https://devblogs.microsoft.com/typescript/announcing-typescript-4-0-beta/#variadic-tuple-types)
- useful for [simplified Reducer-like State](https://www.reddit.com/r/reactjs/comments/hu0ytg/simplified_reducerlike_state_using_typescript_40/)
+- [Custom JSX Factories](https://devblogs.microsoft.com/typescript/announcing-typescript-4-0/#custom-jsx-factories)
+
+It's for custom pragmas with Preact
+
+```tsx
+// Note: these pragma comments need to be written
+// with a JSDoc-style multiline syntax to take effect.
+/** @jsx h */
+/** @jsxFrag Fragment */
+
+import { h, Fragment } from "preact";
+
+let stuff = (
+ <>
+
Hello
+ >
+);
+// transformed to
+let stuff = h(Fragment, null, h("div", null, "Hello"));
+```
+
Possibly in 4.1
+- 4.1 plan https://github.com/microsoft/TypeScript/issues/40124
- [Recursive Conditional Types](https://github.com/microsoft/TypeScript/pull/40002)
## TypeScript Roadmap and Spec
diff --git a/docs/advanced/utility-types.md b/docs/advanced/utility-types.md
index 131eff71..38f4f795 100644
--- a/docs/advanced/utility-types.md
+++ b/docs/advanced/utility-types.md
@@ -4,4 +4,6 @@ title: "Section 0: Utility Types"
sidebar_label: Utility Types
---
-We will assume knowledge of utility types covered in the sister project [`typescript-utilities-guide`](https://github.com/typescript-cheatsheets/typescript-utilities-guide). Look up libraries included there as well for your typing needs.
+We will assume knowledge of utility types covered in the sister project [`typescript-cheatsheets/utilities`](https://github.com/typescript-cheatsheets/utilities). Look up libraries included there as well for your typing needs.
+
+If you intend to maintain a large TS codebase/a nontrivial React+TS library, **we strongly recommend exploring these utilities** so that you don't reinvent the wheel and/or lose sanity trying to do so. Studying their code can also teach you a lot of advanced TS that is not covered here.
diff --git a/docs/basic/recommended/codebases.md b/docs/basic/recommended/codebases.md
new file mode 100644
index 00000000..7070809d
--- /dev/null
+++ b/docs/basic/recommended/codebases.md
@@ -0,0 +1,29 @@
+---
+id: codebases
+title: Recommended React + TypeScript codebases to learn from
+sidebar_label: Codebases to learn from
+---
+
+- https://github.com/jaredpalmer/formik
+- https://github.com/jaredpalmer/react-fns
+- https://github.com/palantir/blueprint
+- https://github.com/Shopify/polaris
+- https://github.com/NullVoxPopuli/react-vs-ember/tree/master/testing/react
+- https://github.com/artsy/reaction
+- https://github.com/benawad/codeponder (with [coding livestream!](https://www.youtube.com/watch?v=D8IJOwdNSkc&list=PLN3n1USn4xlnI6kwzI8WrNgSdG4Z6daCq))
+- https://github.com/artsy/emission (React Native)
+- [@reach/ui's community typings](https://github.com/reach/reach-ui/pull/105)
+
+React Boilerplates:
+
+- https://github.com/rwieruch/nextjs-firebase-authentication: Next.js + Firebase Starter: styled, tested, typed, and authenticated
+- [@jpavon/react-scripts-ts](https://github.com/jpavon/react-scripts-ts) alternative react-scripts with all TypeScript features using [ts-loader](https://github.com/TypeStrong/ts-loader)
+- [webpack config tool](https://webpack.jakoblind.no/) is a visual tool for creating webpack projects with React and TypeScript
+- ready to go template with [Material-UI](https://material-ui.com/), routing and Redux
+
+React Native Boilerplates: _contributed by [@spoeck](https://github.com/typescript-cheatsheets/react-typescript-cheatsheet/pull/20)_
+
+- https://github.com/GeekyAnts/react-native-seed
+- https://github.com/lopezjurip/ReactNativeTS
+- https://github.com/emin93/react-native-template-typescript
+-
diff --git a/docs/basic/recommended/other-resources.md b/docs/basic/recommended/other-resources.md
deleted file mode 100644
index b91f8a06..00000000
--- a/docs/basic/recommended/other-resources.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-id: other_resources
-title: Other React + TypeScript resources
-sidebar_label: Other resources
----
-
-- me!
-- https://www.freecodecamp.org/news/how-to-build-a-todo-app-with-react-typescript-nodejs-and-mongodb/
-- - **HIGHLY HIGHLY RECOMMENDED**, i wrote this repo before knowing about this one, this has a lot of stuff I don't cover, including **REDUX** and **JEST**.
-- [Ultimate React Component Patterns with TypeScript 2.8](https://levelup.gitconnected.com/ultimate-react-component-patterns-with-typescript-2-8-82990c516935)
-- [Basarat's TypeScript gitbook has a React section](https://basarat.gitbook.io/typescript/tsx/react) with an [Egghead.io course](https://egghead.io/courses/use-typescript-to-develop-react-applications) as well.
-- [Palmer Group's TypeScript + React Guidelines](https://github.com/palmerhq/typescript) as well as Jared's other work like [disco.chat](https://github.com/jaredpalmer/disco.chat)
-- [Sindre Sorhus' TypeScript Style Guide](https://github.com/sindresorhus/typescript-definition-style-guide)
-- [TypeScript React Starter Template by Microsoft](https://github.com/Microsoft/TypeScript-React-Starter) A starter template for TypeScript and React with a detailed README describing how to use the two together. Note: this doesnt seem to be frequently updated anymore.
-- [Brian Holt's Intermediate React course on Frontend Masters (paid)](https://frontendmasters.com/courses/intermediate-react/converting-the-app-to-typescript/) - Converting App To TypeScript Section
-- TypeScript conversion:
- - [Lyft's React-To-TypeScript conversion CLI](https://github.com/lyft/react-javascript-to-typescript-transform)
- - [Gustav Wengel's blogpost - converting a React codebase to TypeScript](http://www.gustavwengel.dk/converting-typescript-to-javascript-part-1)
- - [Microsoft React TypeScript conversion guide](https://github.com/Microsoft/TypeScript-React-Conversion-Guide#typescript-react-conversion-guide)
-- [You?](https://github.com/typescript-cheatsheets/react-typescript-cheatsheet/issues/new).
diff --git a/docs/basic/recommended/resources.md b/docs/basic/recommended/resources.md
index bf97e687..1831a9f3 100644
--- a/docs/basic/recommended/resources.md
+++ b/docs/basic/recommended/resources.md
@@ -1,29 +1,21 @@
---
id: resources
-title: Recommended React + TypeScript codebases to learn from
-sidebar_label: Codebases to learn from
+title: Other React + TypeScript resources
+sidebar_label: Other resources
---
-- https://github.com/jaredpalmer/formik
-- https://github.com/jaredpalmer/react-fns
-- https://github.com/palantir/blueprint
-- https://github.com/Shopify/polaris
-- https://github.com/NullVoxPopuli/react-vs-ember/tree/master/testing/react
-- https://github.com/artsy/reaction
-- https://github.com/benawad/codeponder (with [coding livestream!](https://www.youtube.com/watch?v=D8IJOwdNSkc&list=PLN3n1USn4xlnI6kwzI8WrNgSdG4Z6daCq))
-- https://github.com/artsy/emission (React Native)
-- [@reach/ui's community typings](https://github.com/reach/reach-ui/pull/105)
-
-React Boilerplates:
-
-- https://github.com/rwieruch/nextjs-firebase-authentication: Next.js + Firebase Starter: styled, tested, typed, and authenticated
-- [@jpavon/react-scripts-ts](https://github.com/jpavon/react-scripts-ts) alternative react-scripts with all TypeScript features using [ts-loader](https://github.com/TypeStrong/ts-loader)
-- [webpack config tool](https://webpack.jakoblind.no/) is a visual tool for creating webpack projects with React and TypeScript
-- ready to go template with [Material-UI](https://material-ui.com/), routing and Redux
-
-React Native Boilerplates: _contributed by [@spoeck](https://github.com/typescript-cheatsheets/react-typescript-cheatsheet/pull/20)_
-
-- https://github.com/GeekyAnts/react-native-seed
-- https://github.com/lopezjurip/ReactNativeTS
-- https://github.com/emin93/react-native-template-typescript
--
+- me!
+- https://www.freecodecamp.org/news/how-to-build-a-todo-app-with-react-typescript-nodejs-and-mongodb/
+- - **HIGHLY HIGHLY RECOMMENDED**, i wrote this repo before knowing about this one, this has a lot of stuff I don't cover, including **REDUX** and **JEST**.
+- [Ultimate React Component Patterns with TypeScript 2.8](https://levelup.gitconnected.com/ultimate-react-component-patterns-with-typescript-2-8-82990c516935)
+- [Basarat's TypeScript gitbook has a React section](https://basarat.gitbook.io/typescript/tsx/react) with an [Egghead.io course](https://egghead.io/courses/use-typescript-to-develop-react-applications) as well.
+- [Palmer Group's TypeScript + React Guidelines](https://github.com/palmerhq/typescript) as well as Jared's other work like [disco.chat](https://github.com/jaredpalmer/disco.chat)
+- [Sindre Sorhus' TypeScript Style Guide](https://github.com/sindresorhus/typescript-definition-style-guide)
+- [TypeScript React Starter Template by Microsoft](https://github.com/Microsoft/TypeScript-React-Starter) A starter template for TypeScript and React with a detailed README describing how to use the two together. Note: this doesnt seem to be frequently updated anymore.
+- [Brian Holt's Intermediate React course on Frontend Masters (paid)](https://frontendmasters.com/courses/intermediate-react/converting-the-app-to-typescript/) - Converting App To TypeScript Section
+- [TSX Guide](https://jenil.github.io/chota/) by [gojutin](https://github.com/gojutin/www.tsx.guide)
+- TypeScript conversion:
+ - [Lyft's React-To-TypeScript conversion CLI](https://github.com/lyft/react-javascript-to-typescript-transform)
+ - [Gustav Wengel's blogpost - converting a React codebase to TypeScript](http://www.gustavwengel.dk/converting-typescript-to-javascript-part-1)
+ - [Microsoft React TypeScript conversion guide](https://github.com/Microsoft/TypeScript-React-Conversion-Guide#typescript-react-conversion-guide)
+- [You?](https://github.com/typescript-cheatsheets/react-typescript-cheatsheet/issues/new).
diff --git a/docs/migration/from-js.md b/docs/migration/from-js.md
index 66ec7670..81fac039 100644
--- a/docs/migration/from-js.md
+++ b/docs/migration/from-js.md
@@ -8,7 +8,7 @@ title: From JS
- [TypeStat](https://github.com/JoshuaKGoldberg/TypeStat) ([used by Codecademy](https://mobile.twitter.com/JoshuaKGoldberg/status/1159090281314160640))
- [TypeWiz](https://github.com/urish/typewiz)
- [js-to-ts-converter](https://github.com/gregjacobs/js-to-ts-converter)
-- [TS-migrate](https://medium.com/airbnb-engineering/ts-migrate-a-tool-for-migrating-to-typescript-at-scale-cd23bfeb5cc) from Airbnb
+- [TS-migrate](https://github.com/airbnb/ts-migrate) used in [Airbnb's conversion](https://medium.com/airbnb-engineering/ts-migrate-a-tool-for-migrating-to-typescript-at-scale-cd23bfeb5cc)
- [dts-gen](https://github.com/microsoft/dts-gen) - `dts-gen` is a tool that generates TypeScript definition files (.d.ts) from any JavaScript object.
## Manual JS to TS Conversion
@@ -77,7 +77,7 @@ Gradually add [more `strict` mode flags](https://www.typescriptlang.org/docs/han
**More resources**
-- [Adopting TypeScript at Scale - AirBnB's conversion story and strategy](https://www.youtube.com/watch?v=P-J9Eg7hJwE)
+- [Adopting TypeScript at Scale - AirBnB's conversion story and strategy](https://www.youtube.com/watch?v=P-J9Eg7hJwE) - their [ts-migrate tool here](https://medium.com/airbnb-engineering/ts-migrate-a-tool-for-migrating-to-typescript-at-scale-cd23bfeb5cc)
- [Migrating a `create-react-app`/`react-scripts` app to TypeScript](https://facebook.github.io/create-react-app/docs/adding-typescript) - don't use `react-scripts-ts`
- [Migrating an EJECTED CRA app to TS](https://spin.atomicobject.com/2018/07/04/migrating-cra-typescript/)
- [Lyft's JS to TS migration tool](https://github.com/lyft/react-javascript-to-typescript-transform) (includes PropTypes migration)
diff --git a/package.json b/package.json
index c994fa65..606da144 100644
--- a/package.json
+++ b/package.json
@@ -21,6 +21,7 @@
"format-readme": "prettier --write \"README.md\"",
"gen-readme": "node genReadme.js",
"format": "prettier --write \"**/*.md\"",
+ "postinstall": "cd website && yarn",
"start": "yarn --cwd website start"
},
"dependencies": {
diff --git a/website/sidebars.json b/website/sidebars.json
index 33d2e7e2..f81d6c30 100644
--- a/website/sidebars.json
+++ b/website/sidebars.json
@@ -36,11 +36,11 @@
},
{
"type": "category",
- "label": "Recommended React + TypeScript",
+ "label": "Recommendations",
"items": [
- "basic/recommended/resources",
+ "basic/recommended/codebases",
"basic/recommended/talks",
- "basic/recommended/other_resources"
+ "basic/recommended/resources"
]
},
"basic/editor_integration",
@@ -56,26 +56,8 @@
"Advanced": [
"advanced/intro",
"advanced/utility_types",
- {
- "type": "category",
- "label": "Guides",
- "items": [
- "advanced/guides/render_props",
- "advanced/guides/hocs",
- "advanced/guides/conditionally_rendering",
- "advanced/guides/polymorphic_components",
- "advanced/guides/generic_components",
- "advanced/guides/type_component_diff_props",
- "advanced/guides/props_one_other_not_both",
- "advanced/guides/props_optionally_pass_one",
- "advanced/guides/omit_attr",
- "advanced/guides/type_zoo",
- "advanced/guides/extract_props",
- "advanced/guides/handling_exceptions",
- "advanced/guides/third_party_libs"
- ]
- },
- "advanced/patterns",
+ "advanced/patterns_by_usecase",
+ "advanced/patterns_by_version",
"advanced/misc_concerns",
"advanced/types_react_api"
],