From 82914717746dc6e07792f4f34379e5ed8cf759ea Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 10 Jul 2023 11:31:00 +0100 Subject: [PATCH 001/105] Added as prop stuff --- .gitignore | 3 +- package.json | 16 +++++++-- .../51-required-context.problem.tsx} | 0 .../51-required-context.solution.1.tsx} | 0 .../51-required-context.solution.2.tsx} | 0 ...stand-react-namespace-export.explainer.ts} | 0 ...3-understanding-jsx-element.explainer.tsx} | 0 ...54-strongly-typing-children.explainer.tsx} | 0 ...ding-jsx-intrinsic-elements.explainer.tsx} | 0 ...-appending-to-global-namespace.problem.ts} | 0 ...appending-to-global-namespace.solution.ts} | 0 ...on-merging-in-global-namespace.problem.ts} | 0 ...n-merging-in-global-namespace.solution.ts} | 0 ... => 58-add-new-global-element.problem.tsx} | 0 ...=> 58-add-new-global-element.solution.tsx} | 0 ...r.tsx => 59-html-attributes.explainer.tsx} | 0 ...add-attribute-to-all-elements.problem.tsx} | 0 ...dd-attribute-to-all-elements.solution.tsx} | 0 ...tsx => 61-lazy-load-component.problem.tsx} | 0 ...sx => 61-lazy-load-component.solution.tsx} | 0 ...enerics-in-generic-components.problem.tsx} | 0 ...-forward-ref-with-generics.explainer.1.tsx | 4 +-- ...-forward-ref-as-local-function.problem.tsx | 36 +++++++++++++++++++ ...forward-ref-as-local-function.solution.tsx | 31 ++++++++++++++++ ...{65-hoc.problem.tsx => 66-hoc.problem.tsx} | 0 ...5-hoc.solution.tsx => 66-hoc.solution.tsx} | 0 ...of-components-with-same-props.problem.tsx} | 0 ...components-with-same-props.solution.1.tsx} | 0 ...components-with-same-props.solution.2.tsx} | 0 ...s-prop-with-custom-components.solution.tsx | 16 --------- ...rop.problem.tsx => 68-as-prop.problem.tsx} | 0 ...lution.1.tsx => 68-as-prop.solution.1.tsx} | 0 ...lution.2.tsx => 68-as-prop.solution.2.tsx} | 0 ...s-prop-with-custom-components.problem.tsx} | 0 ...s-prop-with-custom-components.solution.tsx | 23 ++++++++++++ .../70-as-prop-with-default.problem.tsx | 36 +++++++++++++++++++ .../70-as-prop-with-default.solution.tsx | 35 ++++++++++++++++++ ...r.tsx => 71-react-hook-form.explainer.tsx} | 0 ...=> 72-react-hook-form-wrapper.problem.tsx} | 0 ...> 72-react-hook-form-wrapper.solution.tsx} | 0 ...roblem.tsx => 73-react-select.problem.tsx} | 0 ...ution.tsx => 73-react-select.solution.tsx} | 0 ...plainer.ts => 74-react-query.explainer.ts} | 0 ...m.ts => 75-react-query-wrapper.problem.ts} | 0 ....ts => 75-react-query-wrapper.solution.ts} | 0 45 files changed, 179 insertions(+), 21 deletions(-) rename src/{08-advanced-patterns/62-required-context.problem.tsx => 06-advanced-hooks/51-required-context.problem.tsx} (100%) rename src/{08-advanced-patterns/62-required-context.solution.1.tsx => 06-advanced-hooks/51-required-context.solution.1.tsx} (100%) rename src/{08-advanced-patterns/62-required-context.solution.2.tsx => 06-advanced-hooks/51-required-context.solution.2.tsx} (100%) rename src/07-types-deep-dive/{51-understand-react-namespace-export.explainer.ts => 52-understand-react-namespace-export.explainer.ts} (100%) rename src/07-types-deep-dive/{52-understanding-jsx-element.explainer.tsx => 53-understanding-jsx-element.explainer.tsx} (100%) rename src/07-types-deep-dive/{53-strongly-typing-children.explainer.tsx => 54-strongly-typing-children.explainer.tsx} (100%) rename src/07-types-deep-dive/{54-understanding-jsx-intrinsic-elements.explainer.tsx => 55-understanding-jsx-intrinsic-elements.explainer.tsx} (100%) rename src/07-types-deep-dive/{55-appending-to-global-namespace.problem.ts => 56-appending-to-global-namespace.problem.ts} (100%) rename src/07-types-deep-dive/{55-appending-to-global-namespace.solution.ts => 56-appending-to-global-namespace.solution.ts} (100%) rename src/07-types-deep-dive/{56-declaration-merging-in-global-namespace.problem.ts => 57-declaration-merging-in-global-namespace.problem.ts} (100%) rename src/07-types-deep-dive/{56-declaration-merging-in-global-namespace.solution.ts => 57-declaration-merging-in-global-namespace.solution.ts} (100%) rename src/07-types-deep-dive/{57-add-new-global-element.problem.tsx => 58-add-new-global-element.problem.tsx} (100%) rename src/07-types-deep-dive/{57-add-new-global-element.solution.tsx => 58-add-new-global-element.solution.tsx} (100%) rename src/07-types-deep-dive/{58-html-attributes.explainer.tsx => 59-html-attributes.explainer.tsx} (100%) rename src/07-types-deep-dive/{59-add-attribute-to-all-elements.problem.tsx => 60-add-attribute-to-all-elements.problem.tsx} (100%) rename src/07-types-deep-dive/{59-add-attribute-to-all-elements.solution.tsx => 60-add-attribute-to-all-elements.solution.tsx} (100%) rename src/08-advanced-patterns/{60-lazy-load-component.problem.tsx => 61-lazy-load-component.problem.tsx} (100%) rename src/08-advanced-patterns/{60-lazy-load-component.solution.tsx => 61-lazy-load-component.solution.tsx} (100%) rename src/08-advanced-patterns/{61-const-generics-in-generic-components.problem.tsx => 62-const-generics-in-generic-components.problem.tsx} (100%) create mode 100644 src/08-advanced-patterns/65-forward-ref-as-local-function.problem.tsx create mode 100644 src/08-advanced-patterns/65-forward-ref-as-local-function.solution.tsx rename src/08-advanced-patterns/{65-hoc.problem.tsx => 66-hoc.problem.tsx} (100%) rename src/08-advanced-patterns/{65-hoc.solution.tsx => 66-hoc.solution.tsx} (100%) rename src/08-advanced-patterns/{66-record-of-components-with-same-props.problem.tsx => 67-record-of-components-with-same-props.problem.tsx} (100%) rename src/08-advanced-patterns/{66-record-of-components-with-same-props.solution.1.tsx => 67-record-of-components-with-same-props.solution.1.tsx} (100%) rename src/08-advanced-patterns/{66-record-of-components-with-same-props.solution.2.tsx => 67-record-of-components-with-same-props.solution.2.tsx} (100%) delete mode 100644 src/08-advanced-patterns/68-as-prop-with-custom-components.solution.tsx rename src/08-advanced-patterns/{67-as-prop.problem.tsx => 68-as-prop.problem.tsx} (100%) rename src/08-advanced-patterns/{67-as-prop.solution.1.tsx => 68-as-prop.solution.1.tsx} (100%) rename src/08-advanced-patterns/{67-as-prop.solution.2.tsx => 68-as-prop.solution.2.tsx} (100%) rename src/08-advanced-patterns/{68-as-prop-with-custom-components.problem.tsx => 69-as-prop-with-custom-components.problem.tsx} (100%) create mode 100644 src/08-advanced-patterns/69-as-prop-with-custom-components.solution.tsx create mode 100644 src/08-advanced-patterns/70-as-prop-with-default.problem.tsx create mode 100644 src/08-advanced-patterns/70-as-prop-with-default.solution.tsx rename src/09-external-libraries/{69-react-hook-form.explainer.tsx => 71-react-hook-form.explainer.tsx} (100%) rename src/09-external-libraries/{70-react-hook-form-wrapper.problem.tsx => 72-react-hook-form-wrapper.problem.tsx} (100%) rename src/09-external-libraries/{70-react-hook-form-wrapper.solution.tsx => 72-react-hook-form-wrapper.solution.tsx} (100%) rename src/09-external-libraries/{71-react-select.problem.tsx => 73-react-select.problem.tsx} (100%) rename src/09-external-libraries/{71-react-select.solution.tsx => 73-react-select.solution.tsx} (100%) rename src/09-external-libraries/{72-react-query.explainer.ts => 74-react-query.explainer.ts} (100%) rename src/09-external-libraries/{73-react-query-wrapper.problem.ts => 75-react-query-wrapper.problem.ts} (100%) rename src/09-external-libraries/{73-react-query-wrapper.solution.ts => 75-react-query-wrapper.solution.ts} (100%) diff --git a/.gitignore b/.gitignore index 55371e5..59ecb4b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules -.vscode \ No newline at end of file +.vscode +tsconfig.temp.json \ No newline at end of file diff --git a/package.json b/package.json index 11a58bd..467b6b2 100644 --- a/package.json +++ b/package.json @@ -144,7 +144,19 @@ "e-65": "tt-cli run 65", "s-65": "tt-cli run 65 --solution", "e-66": "tt-cli run 66", - "s-66": "tt-cli run 66 --solution" + "s-66": "tt-cli run 66 --solution", + "e-43": "tt-cli run 43", + "s-43": "tt-cli run 43 --solution", + "e-67": "tt-cli run 67", + "s-67": "tt-cli run 67 --solution", + "e-68": "tt-cli run 68", + "s-68": "tt-cli run 68 --solution", + "e-70": "tt-cli run 70", + "s-70": "tt-cli run 70 --solution", + "e-71": "tt-cli run 71", + "s-71": "tt-cli run 71 --solution", + "e-73": "tt-cli run 73", + "s-73": "tt-cli run 73 --solution" }, "dependencies": { "@tanstack/react-query": "^4.29.12", @@ -158,4 +170,4 @@ "react-select": "^5.7.3", "zod": "^3.21.4" } -} +} \ No newline at end of file diff --git a/src/08-advanced-patterns/62-required-context.problem.tsx b/src/06-advanced-hooks/51-required-context.problem.tsx similarity index 100% rename from src/08-advanced-patterns/62-required-context.problem.tsx rename to src/06-advanced-hooks/51-required-context.problem.tsx diff --git a/src/08-advanced-patterns/62-required-context.solution.1.tsx b/src/06-advanced-hooks/51-required-context.solution.1.tsx similarity index 100% rename from src/08-advanced-patterns/62-required-context.solution.1.tsx rename to src/06-advanced-hooks/51-required-context.solution.1.tsx diff --git a/src/08-advanced-patterns/62-required-context.solution.2.tsx b/src/06-advanced-hooks/51-required-context.solution.2.tsx similarity index 100% rename from src/08-advanced-patterns/62-required-context.solution.2.tsx rename to src/06-advanced-hooks/51-required-context.solution.2.tsx diff --git a/src/07-types-deep-dive/51-understand-react-namespace-export.explainer.ts b/src/07-types-deep-dive/52-understand-react-namespace-export.explainer.ts similarity index 100% rename from src/07-types-deep-dive/51-understand-react-namespace-export.explainer.ts rename to src/07-types-deep-dive/52-understand-react-namespace-export.explainer.ts diff --git a/src/07-types-deep-dive/52-understanding-jsx-element.explainer.tsx b/src/07-types-deep-dive/53-understanding-jsx-element.explainer.tsx similarity index 100% rename from src/07-types-deep-dive/52-understanding-jsx-element.explainer.tsx rename to src/07-types-deep-dive/53-understanding-jsx-element.explainer.tsx diff --git a/src/07-types-deep-dive/53-strongly-typing-children.explainer.tsx b/src/07-types-deep-dive/54-strongly-typing-children.explainer.tsx similarity index 100% rename from src/07-types-deep-dive/53-strongly-typing-children.explainer.tsx rename to src/07-types-deep-dive/54-strongly-typing-children.explainer.tsx diff --git a/src/07-types-deep-dive/54-understanding-jsx-intrinsic-elements.explainer.tsx b/src/07-types-deep-dive/55-understanding-jsx-intrinsic-elements.explainer.tsx similarity index 100% rename from src/07-types-deep-dive/54-understanding-jsx-intrinsic-elements.explainer.tsx rename to src/07-types-deep-dive/55-understanding-jsx-intrinsic-elements.explainer.tsx diff --git a/src/07-types-deep-dive/55-appending-to-global-namespace.problem.ts b/src/07-types-deep-dive/56-appending-to-global-namespace.problem.ts similarity index 100% rename from src/07-types-deep-dive/55-appending-to-global-namespace.problem.ts rename to src/07-types-deep-dive/56-appending-to-global-namespace.problem.ts diff --git a/src/07-types-deep-dive/55-appending-to-global-namespace.solution.ts b/src/07-types-deep-dive/56-appending-to-global-namespace.solution.ts similarity index 100% rename from src/07-types-deep-dive/55-appending-to-global-namespace.solution.ts rename to src/07-types-deep-dive/56-appending-to-global-namespace.solution.ts diff --git a/src/07-types-deep-dive/56-declaration-merging-in-global-namespace.problem.ts b/src/07-types-deep-dive/57-declaration-merging-in-global-namespace.problem.ts similarity index 100% rename from src/07-types-deep-dive/56-declaration-merging-in-global-namespace.problem.ts rename to src/07-types-deep-dive/57-declaration-merging-in-global-namespace.problem.ts diff --git a/src/07-types-deep-dive/56-declaration-merging-in-global-namespace.solution.ts b/src/07-types-deep-dive/57-declaration-merging-in-global-namespace.solution.ts similarity index 100% rename from src/07-types-deep-dive/56-declaration-merging-in-global-namespace.solution.ts rename to src/07-types-deep-dive/57-declaration-merging-in-global-namespace.solution.ts diff --git a/src/07-types-deep-dive/57-add-new-global-element.problem.tsx b/src/07-types-deep-dive/58-add-new-global-element.problem.tsx similarity index 100% rename from src/07-types-deep-dive/57-add-new-global-element.problem.tsx rename to src/07-types-deep-dive/58-add-new-global-element.problem.tsx diff --git a/src/07-types-deep-dive/57-add-new-global-element.solution.tsx b/src/07-types-deep-dive/58-add-new-global-element.solution.tsx similarity index 100% rename from src/07-types-deep-dive/57-add-new-global-element.solution.tsx rename to src/07-types-deep-dive/58-add-new-global-element.solution.tsx diff --git a/src/07-types-deep-dive/58-html-attributes.explainer.tsx b/src/07-types-deep-dive/59-html-attributes.explainer.tsx similarity index 100% rename from src/07-types-deep-dive/58-html-attributes.explainer.tsx rename to src/07-types-deep-dive/59-html-attributes.explainer.tsx diff --git a/src/07-types-deep-dive/59-add-attribute-to-all-elements.problem.tsx b/src/07-types-deep-dive/60-add-attribute-to-all-elements.problem.tsx similarity index 100% rename from src/07-types-deep-dive/59-add-attribute-to-all-elements.problem.tsx rename to src/07-types-deep-dive/60-add-attribute-to-all-elements.problem.tsx diff --git a/src/07-types-deep-dive/59-add-attribute-to-all-elements.solution.tsx b/src/07-types-deep-dive/60-add-attribute-to-all-elements.solution.tsx similarity index 100% rename from src/07-types-deep-dive/59-add-attribute-to-all-elements.solution.tsx rename to src/07-types-deep-dive/60-add-attribute-to-all-elements.solution.tsx diff --git a/src/08-advanced-patterns/60-lazy-load-component.problem.tsx b/src/08-advanced-patterns/61-lazy-load-component.problem.tsx similarity index 100% rename from src/08-advanced-patterns/60-lazy-load-component.problem.tsx rename to src/08-advanced-patterns/61-lazy-load-component.problem.tsx diff --git a/src/08-advanced-patterns/60-lazy-load-component.solution.tsx b/src/08-advanced-patterns/61-lazy-load-component.solution.tsx similarity index 100% rename from src/08-advanced-patterns/60-lazy-load-component.solution.tsx rename to src/08-advanced-patterns/61-lazy-load-component.solution.tsx diff --git a/src/08-advanced-patterns/61-const-generics-in-generic-components.problem.tsx b/src/08-advanced-patterns/62-const-generics-in-generic-components.problem.tsx similarity index 100% rename from src/08-advanced-patterns/61-const-generics-in-generic-components.problem.tsx rename to src/08-advanced-patterns/62-const-generics-in-generic-components.problem.tsx diff --git a/src/08-advanced-patterns/64-forward-ref-with-generics.explainer.1.tsx b/src/08-advanced-patterns/64-forward-ref-with-generics.explainer.1.tsx index 12829e0..8f96727 100644 --- a/src/08-advanced-patterns/64-forward-ref-with-generics.explainer.1.tsx +++ b/src/08-advanced-patterns/64-forward-ref-with-generics.explainer.1.tsx @@ -17,8 +17,8 @@ type Props = { // declare module "react" { // function forwardRef( -// render: (props: P, ref: React.Ref) => React.ReactNode | null, -// ): (props: P & React.RefAttributes) => React.ReactNode | null; +// render: (props: P, ref: React.Ref) => React.ReactNode, +// ): (props: P & React.RefAttributes) => React.ReactNode; // } /** diff --git a/src/08-advanced-patterns/65-forward-ref-as-local-function.problem.tsx b/src/08-advanced-patterns/65-forward-ref-as-local-function.problem.tsx new file mode 100644 index 0000000..e78bbaf --- /dev/null +++ b/src/08-advanced-patterns/65-forward-ref-as-local-function.problem.tsx @@ -0,0 +1,36 @@ +import { ForwardedRef, forwardRef } from "react"; +import { Equal, Expect } from "../helpers/type-utils"; + +/** + * Using the forward-ref-with-generics explanation as a guide, + * give fixedForwardRef a type signature that allows it to + * work with the example below. + */ +function fixedForwardRef( + render: (props: any, ref: any) => any, +): (props: any) => any { + return forwardRef(render) as any; +} + +type Props = { + data: T[]; + renderRow: (item: T) => React.ReactNode; +}; + +export const Table = (props: Props, ref: ForwardedRef) => { + return null; +}; + +const ForwardReffedTable = fixedForwardRef(Table); + +const Parent = () => { + return ( + { + type test = Expect>; + return
123
; + }} + >
+ ); +}; diff --git a/src/08-advanced-patterns/65-forward-ref-as-local-function.solution.tsx b/src/08-advanced-patterns/65-forward-ref-as-local-function.solution.tsx new file mode 100644 index 0000000..9c4652c --- /dev/null +++ b/src/08-advanced-patterns/65-forward-ref-as-local-function.solution.tsx @@ -0,0 +1,31 @@ +import { ForwardedRef, forwardRef } from "react"; +import { Equal, Expect } from "../helpers/type-utils"; + +function fixedForwardRef( + render: (props: P, ref: React.Ref) => React.ReactNode, +): (props: P & React.RefAttributes) => React.ReactNode { + return forwardRef(render) as any; +} + +type Props = { + data: T[]; + renderRow: (item: T) => React.ReactNode; +}; + +export const Table = (props: Props, ref: ForwardedRef) => { + return null; +}; + +const ForwardReffedTable = fixedForwardRef(Table); + +const Parent = () => { + return ( + { + type test = Expect>; + return
123
; + }} + >
+ ); +}; diff --git a/src/08-advanced-patterns/65-hoc.problem.tsx b/src/08-advanced-patterns/66-hoc.problem.tsx similarity index 100% rename from src/08-advanced-patterns/65-hoc.problem.tsx rename to src/08-advanced-patterns/66-hoc.problem.tsx diff --git a/src/08-advanced-patterns/65-hoc.solution.tsx b/src/08-advanced-patterns/66-hoc.solution.tsx similarity index 100% rename from src/08-advanced-patterns/65-hoc.solution.tsx rename to src/08-advanced-patterns/66-hoc.solution.tsx diff --git a/src/08-advanced-patterns/66-record-of-components-with-same-props.problem.tsx b/src/08-advanced-patterns/67-record-of-components-with-same-props.problem.tsx similarity index 100% rename from src/08-advanced-patterns/66-record-of-components-with-same-props.problem.tsx rename to src/08-advanced-patterns/67-record-of-components-with-same-props.problem.tsx diff --git a/src/08-advanced-patterns/66-record-of-components-with-same-props.solution.1.tsx b/src/08-advanced-patterns/67-record-of-components-with-same-props.solution.1.tsx similarity index 100% rename from src/08-advanced-patterns/66-record-of-components-with-same-props.solution.1.tsx rename to src/08-advanced-patterns/67-record-of-components-with-same-props.solution.1.tsx diff --git a/src/08-advanced-patterns/66-record-of-components-with-same-props.solution.2.tsx b/src/08-advanced-patterns/67-record-of-components-with-same-props.solution.2.tsx similarity index 100% rename from src/08-advanced-patterns/66-record-of-components-with-same-props.solution.2.tsx rename to src/08-advanced-patterns/67-record-of-components-with-same-props.solution.2.tsx diff --git a/src/08-advanced-patterns/68-as-prop-with-custom-components.solution.tsx b/src/08-advanced-patterns/68-as-prop-with-custom-components.solution.tsx deleted file mode 100644 index 683f82c..0000000 --- a/src/08-advanced-patterns/68-as-prop-with-custom-components.solution.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import React, { ComponentProps, ComponentType } from "react"; - -export const Wrapper = >( - props: { - as: T; - } & ComponentProps, -) => { - const Comp = props.as; - return ; -}; - -const Link = (props: { href: string; children?: React.ReactNode }) => { - return {props.children}; -}; - -; diff --git a/src/08-advanced-patterns/67-as-prop.problem.tsx b/src/08-advanced-patterns/68-as-prop.problem.tsx similarity index 100% rename from src/08-advanced-patterns/67-as-prop.problem.tsx rename to src/08-advanced-patterns/68-as-prop.problem.tsx diff --git a/src/08-advanced-patterns/67-as-prop.solution.1.tsx b/src/08-advanced-patterns/68-as-prop.solution.1.tsx similarity index 100% rename from src/08-advanced-patterns/67-as-prop.solution.1.tsx rename to src/08-advanced-patterns/68-as-prop.solution.1.tsx diff --git a/src/08-advanced-patterns/67-as-prop.solution.2.tsx b/src/08-advanced-patterns/68-as-prop.solution.2.tsx similarity index 100% rename from src/08-advanced-patterns/67-as-prop.solution.2.tsx rename to src/08-advanced-patterns/68-as-prop.solution.2.tsx diff --git a/src/08-advanced-patterns/68-as-prop-with-custom-components.problem.tsx b/src/08-advanced-patterns/69-as-prop-with-custom-components.problem.tsx similarity index 100% rename from src/08-advanced-patterns/68-as-prop-with-custom-components.problem.tsx rename to src/08-advanced-patterns/69-as-prop-with-custom-components.problem.tsx diff --git a/src/08-advanced-patterns/69-as-prop-with-custom-components.solution.tsx b/src/08-advanced-patterns/69-as-prop-with-custom-components.solution.tsx new file mode 100644 index 0000000..6af9b70 --- /dev/null +++ b/src/08-advanced-patterns/69-as-prop-with-custom-components.solution.tsx @@ -0,0 +1,23 @@ +import React, { ComponentPropsWithoutRef, ElementType } from "react"; +import { Equal, Expect } from "../helpers/type-utils"; + +export const Wrapper = >( + props: { + as: T; + } & ComponentPropsWithoutRef, +) => { + const Comp = props.as; + return ; +}; + +const Link = (props: { href: string; children?: React.ReactNode }) => { + return {props.children}; +}; + +; + { + type test = Expect>>; + }} +/>; diff --git a/src/08-advanced-patterns/70-as-prop-with-default.problem.tsx b/src/08-advanced-patterns/70-as-prop-with-default.problem.tsx new file mode 100644 index 0000000..e016fee --- /dev/null +++ b/src/08-advanced-patterns/70-as-prop-with-default.problem.tsx @@ -0,0 +1,36 @@ +import { ComponentPropsWithoutRef, ElementType } from "react"; +import { Equal, Expect } from "../helpers/type-utils"; + +export const Link = >( + props: { + as: T; + } & ComponentPropsWithoutRef, +) => { + const { as: Comp, ...rest } = props; + return ; +}; + +// Should be a 'a' tag by default! +; + +const Custom = (props: { thisIsRequired: boolean }) => { + return null; +}; + +; + +// @ts-expect-error Property 'thisIsRequired' is missing +; + + { + type test = Expect>>; + }} +>; + +; diff --git a/src/08-advanced-patterns/70-as-prop-with-default.solution.tsx b/src/08-advanced-patterns/70-as-prop-with-default.solution.tsx new file mode 100644 index 0000000..a2fbc60 --- /dev/null +++ b/src/08-advanced-patterns/70-as-prop-with-default.solution.tsx @@ -0,0 +1,35 @@ +import { ComponentPropsWithoutRef, ElementType } from "react"; +import { Equal, Expect } from "../helpers/type-utils"; + +export const Link = = "a">( + props: { + as?: T; + } & ComponentPropsWithoutRef, +) => { + const { as: Comp = "a", ...rest } = props; + return ; +}; + +; + +const Custom = (props: { thisIsRequired: boolean }) => { + return null; +}; + +; + +// @ts-expect-error Property 'thisIsRequired' is missing +; + + { + type test = Expect>>; + }} +>; + +; diff --git a/src/09-external-libraries/69-react-hook-form.explainer.tsx b/src/09-external-libraries/71-react-hook-form.explainer.tsx similarity index 100% rename from src/09-external-libraries/69-react-hook-form.explainer.tsx rename to src/09-external-libraries/71-react-hook-form.explainer.tsx diff --git a/src/09-external-libraries/70-react-hook-form-wrapper.problem.tsx b/src/09-external-libraries/72-react-hook-form-wrapper.problem.tsx similarity index 100% rename from src/09-external-libraries/70-react-hook-form-wrapper.problem.tsx rename to src/09-external-libraries/72-react-hook-form-wrapper.problem.tsx diff --git a/src/09-external-libraries/70-react-hook-form-wrapper.solution.tsx b/src/09-external-libraries/72-react-hook-form-wrapper.solution.tsx similarity index 100% rename from src/09-external-libraries/70-react-hook-form-wrapper.solution.tsx rename to src/09-external-libraries/72-react-hook-form-wrapper.solution.tsx diff --git a/src/09-external-libraries/71-react-select.problem.tsx b/src/09-external-libraries/73-react-select.problem.tsx similarity index 100% rename from src/09-external-libraries/71-react-select.problem.tsx rename to src/09-external-libraries/73-react-select.problem.tsx diff --git a/src/09-external-libraries/71-react-select.solution.tsx b/src/09-external-libraries/73-react-select.solution.tsx similarity index 100% rename from src/09-external-libraries/71-react-select.solution.tsx rename to src/09-external-libraries/73-react-select.solution.tsx diff --git a/src/09-external-libraries/72-react-query.explainer.ts b/src/09-external-libraries/74-react-query.explainer.ts similarity index 100% rename from src/09-external-libraries/72-react-query.explainer.ts rename to src/09-external-libraries/74-react-query.explainer.ts diff --git a/src/09-external-libraries/73-react-query-wrapper.problem.ts b/src/09-external-libraries/75-react-query-wrapper.problem.ts similarity index 100% rename from src/09-external-libraries/73-react-query-wrapper.problem.ts rename to src/09-external-libraries/75-react-query-wrapper.problem.ts diff --git a/src/09-external-libraries/73-react-query-wrapper.solution.ts b/src/09-external-libraries/75-react-query-wrapper.solution.ts similarity index 100% rename from src/09-external-libraries/73-react-query-wrapper.solution.ts rename to src/09-external-libraries/75-react-query-wrapper.solution.ts From 85ec36fe09f171f187225460343c7359e61050c9 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 10 Jul 2023 12:03:12 +0100 Subject: [PATCH 002/105] Added currying hooks --- .../51-currying-hooks.problem.ts | 39 +++++++++++++++++++ .../51-currying-hooks.solution.ts | 33 ++++++++++++++++ ...em.tsx => 52-required-context.problem.tsx} | 0 ...tsx => 52-required-context.solution.1.tsx} | 0 ...tsx => 52-required-context.solution.2.tsx} | 0 ...stand-react-namespace-export.explainer.ts} | 0 ...4-understanding-jsx-element.explainer.tsx} | 0 ...55-strongly-typing-children.explainer.tsx} | 0 ...ding-jsx-intrinsic-elements.explainer.tsx} | 0 ...-appending-to-global-namespace.problem.ts} | 0 ...appending-to-global-namespace.solution.ts} | 0 ...on-merging-in-global-namespace.problem.ts} | 0 ...n-merging-in-global-namespace.solution.ts} | 0 ... => 59-add-new-global-element.problem.tsx} | 0 ...=> 59-add-new-global-element.solution.tsx} | 0 ...r.tsx => 60-html-attributes.explainer.tsx} | 0 ...add-attribute-to-all-elements.problem.tsx} | 0 ...dd-attribute-to-all-elements.solution.tsx} | 0 ...tsx => 62-lazy-load-component.problem.tsx} | 0 ...sx => 62-lazy-load-component.solution.tsx} | 0 ...enerics-in-generic-components.problem.tsx} | 0 ...roblem.tsx => 64-render-props.problem.tsx} | 0 ...ution.tsx => 64-render-props.solution.tsx} | 0 ...forward-ref-with-generics.explainer.1.tsx} | 0 ...forward-ref-with-generics.explainer.2.tsx} | 0 ...-forward-ref-with-generics.explainer.3.ts} | 0 ...forward-ref-as-local-function.problem.tsx} | 0 ...orward-ref-as-local-function.solution.tsx} | 0 ...{66-hoc.problem.tsx => 67-hoc.problem.tsx} | 0 ...6-hoc.solution.tsx => 67-hoc.solution.tsx} | 0 ...of-components-with-same-props.problem.tsx} | 0 ...components-with-same-props.solution.1.tsx} | 0 ...components-with-same-props.solution.2.tsx} | 0 ...rop.problem.tsx => 69-as-prop.problem.tsx} | 0 ...lution.1.tsx => 69-as-prop.solution.1.tsx} | 0 ...lution.2.tsx => 69-as-prop.solution.2.tsx} | 0 ...s-prop-with-custom-components.problem.tsx} | 0 ...-prop-with-custom-components.solution.tsx} | 0 ...sx => 71-as-prop-with-default.problem.tsx} | 0 ...x => 71-as-prop-with-default.solution.tsx} | 0 ...r.tsx => 72-react-hook-form.explainer.tsx} | 0 ...=> 73-react-hook-form-wrapper.problem.tsx} | 0 ...> 73-react-hook-form-wrapper.solution.tsx} | 0 ...roblem.tsx => 74-react-select.problem.tsx} | 0 ...ution.tsx => 74-react-select.solution.tsx} | 0 ...plainer.ts => 75-react-query.explainer.ts} | 0 ...m.ts => 76-react-query-wrapper.problem.ts} | 0 ....ts => 76-react-query-wrapper.solution.ts} | 0 48 files changed, 72 insertions(+) create mode 100644 src/06-advanced-hooks/51-currying-hooks.problem.ts create mode 100644 src/06-advanced-hooks/51-currying-hooks.solution.ts rename src/06-advanced-hooks/{51-required-context.problem.tsx => 52-required-context.problem.tsx} (100%) rename src/06-advanced-hooks/{51-required-context.solution.1.tsx => 52-required-context.solution.1.tsx} (100%) rename src/06-advanced-hooks/{51-required-context.solution.2.tsx => 52-required-context.solution.2.tsx} (100%) rename src/07-types-deep-dive/{52-understand-react-namespace-export.explainer.ts => 53-understand-react-namespace-export.explainer.ts} (100%) rename src/07-types-deep-dive/{53-understanding-jsx-element.explainer.tsx => 54-understanding-jsx-element.explainer.tsx} (100%) rename src/07-types-deep-dive/{54-strongly-typing-children.explainer.tsx => 55-strongly-typing-children.explainer.tsx} (100%) rename src/07-types-deep-dive/{55-understanding-jsx-intrinsic-elements.explainer.tsx => 56-understanding-jsx-intrinsic-elements.explainer.tsx} (100%) rename src/07-types-deep-dive/{56-appending-to-global-namespace.problem.ts => 57-appending-to-global-namespace.problem.ts} (100%) rename src/07-types-deep-dive/{56-appending-to-global-namespace.solution.ts => 57-appending-to-global-namespace.solution.ts} (100%) rename src/07-types-deep-dive/{57-declaration-merging-in-global-namespace.problem.ts => 58-declaration-merging-in-global-namespace.problem.ts} (100%) rename src/07-types-deep-dive/{57-declaration-merging-in-global-namespace.solution.ts => 58-declaration-merging-in-global-namespace.solution.ts} (100%) rename src/07-types-deep-dive/{58-add-new-global-element.problem.tsx => 59-add-new-global-element.problem.tsx} (100%) rename src/07-types-deep-dive/{58-add-new-global-element.solution.tsx => 59-add-new-global-element.solution.tsx} (100%) rename src/07-types-deep-dive/{59-html-attributes.explainer.tsx => 60-html-attributes.explainer.tsx} (100%) rename src/07-types-deep-dive/{60-add-attribute-to-all-elements.problem.tsx => 61-add-attribute-to-all-elements.problem.tsx} (100%) rename src/07-types-deep-dive/{60-add-attribute-to-all-elements.solution.tsx => 61-add-attribute-to-all-elements.solution.tsx} (100%) rename src/08-advanced-patterns/{61-lazy-load-component.problem.tsx => 62-lazy-load-component.problem.tsx} (100%) rename src/08-advanced-patterns/{61-lazy-load-component.solution.tsx => 62-lazy-load-component.solution.tsx} (100%) rename src/08-advanced-patterns/{62-const-generics-in-generic-components.problem.tsx => 63-const-generics-in-generic-components.problem.tsx} (100%) rename src/08-advanced-patterns/{63-render-props.problem.tsx => 64-render-props.problem.tsx} (100%) rename src/08-advanced-patterns/{63-render-props.solution.tsx => 64-render-props.solution.tsx} (100%) rename src/08-advanced-patterns/{64-forward-ref-with-generics.explainer.1.tsx => 65-forward-ref-with-generics.explainer.1.tsx} (100%) rename src/08-advanced-patterns/{64-forward-ref-with-generics.explainer.2.tsx => 65-forward-ref-with-generics.explainer.2.tsx} (100%) rename src/08-advanced-patterns/{64-forward-ref-with-generics.explainer.3.ts => 65-forward-ref-with-generics.explainer.3.ts} (100%) rename src/08-advanced-patterns/{65-forward-ref-as-local-function.problem.tsx => 66-forward-ref-as-local-function.problem.tsx} (100%) rename src/08-advanced-patterns/{65-forward-ref-as-local-function.solution.tsx => 66-forward-ref-as-local-function.solution.tsx} (100%) rename src/08-advanced-patterns/{66-hoc.problem.tsx => 67-hoc.problem.tsx} (100%) rename src/08-advanced-patterns/{66-hoc.solution.tsx => 67-hoc.solution.tsx} (100%) rename src/08-advanced-patterns/{67-record-of-components-with-same-props.problem.tsx => 68-record-of-components-with-same-props.problem.tsx} (100%) rename src/08-advanced-patterns/{67-record-of-components-with-same-props.solution.1.tsx => 68-record-of-components-with-same-props.solution.1.tsx} (100%) rename src/08-advanced-patterns/{67-record-of-components-with-same-props.solution.2.tsx => 68-record-of-components-with-same-props.solution.2.tsx} (100%) rename src/08-advanced-patterns/{68-as-prop.problem.tsx => 69-as-prop.problem.tsx} (100%) rename src/08-advanced-patterns/{68-as-prop.solution.1.tsx => 69-as-prop.solution.1.tsx} (100%) rename src/08-advanced-patterns/{68-as-prop.solution.2.tsx => 69-as-prop.solution.2.tsx} (100%) rename src/08-advanced-patterns/{69-as-prop-with-custom-components.problem.tsx => 70-as-prop-with-custom-components.problem.tsx} (100%) rename src/08-advanced-patterns/{69-as-prop-with-custom-components.solution.tsx => 70-as-prop-with-custom-components.solution.tsx} (100%) rename src/08-advanced-patterns/{70-as-prop-with-default.problem.tsx => 71-as-prop-with-default.problem.tsx} (100%) rename src/08-advanced-patterns/{70-as-prop-with-default.solution.tsx => 71-as-prop-with-default.solution.tsx} (100%) rename src/09-external-libraries/{71-react-hook-form.explainer.tsx => 72-react-hook-form.explainer.tsx} (100%) rename src/09-external-libraries/{72-react-hook-form-wrapper.problem.tsx => 73-react-hook-form-wrapper.problem.tsx} (100%) rename src/09-external-libraries/{72-react-hook-form-wrapper.solution.tsx => 73-react-hook-form-wrapper.solution.tsx} (100%) rename src/09-external-libraries/{73-react-select.problem.tsx => 74-react-select.problem.tsx} (100%) rename src/09-external-libraries/{73-react-select.solution.tsx => 74-react-select.solution.tsx} (100%) rename src/09-external-libraries/{74-react-query.explainer.ts => 75-react-query.explainer.ts} (100%) rename src/09-external-libraries/{75-react-query-wrapper.problem.ts => 76-react-query-wrapper.problem.ts} (100%) rename src/09-external-libraries/{75-react-query-wrapper.solution.ts => 76-react-query-wrapper.solution.ts} (100%) diff --git a/src/06-advanced-hooks/51-currying-hooks.problem.ts b/src/06-advanced-hooks/51-currying-hooks.problem.ts new file mode 100644 index 0000000..ccce13c --- /dev/null +++ b/src/06-advanced-hooks/51-currying-hooks.problem.ts @@ -0,0 +1,39 @@ +import { DependencyList, useMemo, useState } from "react"; +import { Equal, Expect } from "../helpers/type-utils"; + +const useCustomState = (initial: TValue) => { + const [value, set] = useState(initial); + + return { + value, + set, + /** + * Here, we're returning a hook from our initial hook! + * This is a great way to compose behaviour. + * + * BUT - useComputed takes in a function which can return + * any type. We want to make sure that the type of the + * thing returned is inferred properly. + */ + useComputed: (factory: (value: any) => any, deps?: DependencyList) => { + return useMemo(() => { + return factory(value); + }, [value, ...(deps || [])]); + }, + }; +}; + +const Component = () => { + const arrayOfNums = useCustomState([1, 2, 3, 4, 5, 6, 7, 8]); + + /** + * Currently, this is typed as any. How do we type it + * based on the return type of the function passed to + * useComputed? + */ + const reversedAsString = arrayOfNums.useComputed((nums) => + Array.from(nums).reverse().map(String), + ); + + type test = Expect>; +}; diff --git a/src/06-advanced-hooks/51-currying-hooks.solution.ts b/src/06-advanced-hooks/51-currying-hooks.solution.ts new file mode 100644 index 0000000..95bc7c3 --- /dev/null +++ b/src/06-advanced-hooks/51-currying-hooks.solution.ts @@ -0,0 +1,33 @@ +import { DependencyList, useMemo, useState } from "react"; +import { Equal, Expect } from "../helpers/type-utils"; + +const useCustomState = (initial: TValue) => { + const [value, set] = useState(initial); + + return { + value, + set, + /** + * We can use a generic _inline_ here to ensure + * this all still works. + */ + useComputed: ( + factory: (value: TValue) => TComputed, + deps?: DependencyList, + ) => { + return useMemo(() => { + return factory(value); + }, [value, ...(deps || [])]); + }, + }; +}; + +const Component = () => { + const arrayOfNums = useCustomState([1, 2, 3, 4, 5, 6, 7, 8]); + + const reversedAsString = arrayOfNums.useComputed((nums) => + Array.from(nums).reverse().map(String), + ); + + type test = Expect>; +}; diff --git a/src/06-advanced-hooks/51-required-context.problem.tsx b/src/06-advanced-hooks/52-required-context.problem.tsx similarity index 100% rename from src/06-advanced-hooks/51-required-context.problem.tsx rename to src/06-advanced-hooks/52-required-context.problem.tsx diff --git a/src/06-advanced-hooks/51-required-context.solution.1.tsx b/src/06-advanced-hooks/52-required-context.solution.1.tsx similarity index 100% rename from src/06-advanced-hooks/51-required-context.solution.1.tsx rename to src/06-advanced-hooks/52-required-context.solution.1.tsx diff --git a/src/06-advanced-hooks/51-required-context.solution.2.tsx b/src/06-advanced-hooks/52-required-context.solution.2.tsx similarity index 100% rename from src/06-advanced-hooks/51-required-context.solution.2.tsx rename to src/06-advanced-hooks/52-required-context.solution.2.tsx diff --git a/src/07-types-deep-dive/52-understand-react-namespace-export.explainer.ts b/src/07-types-deep-dive/53-understand-react-namespace-export.explainer.ts similarity index 100% rename from src/07-types-deep-dive/52-understand-react-namespace-export.explainer.ts rename to src/07-types-deep-dive/53-understand-react-namespace-export.explainer.ts diff --git a/src/07-types-deep-dive/53-understanding-jsx-element.explainer.tsx b/src/07-types-deep-dive/54-understanding-jsx-element.explainer.tsx similarity index 100% rename from src/07-types-deep-dive/53-understanding-jsx-element.explainer.tsx rename to src/07-types-deep-dive/54-understanding-jsx-element.explainer.tsx diff --git a/src/07-types-deep-dive/54-strongly-typing-children.explainer.tsx b/src/07-types-deep-dive/55-strongly-typing-children.explainer.tsx similarity index 100% rename from src/07-types-deep-dive/54-strongly-typing-children.explainer.tsx rename to src/07-types-deep-dive/55-strongly-typing-children.explainer.tsx diff --git a/src/07-types-deep-dive/55-understanding-jsx-intrinsic-elements.explainer.tsx b/src/07-types-deep-dive/56-understanding-jsx-intrinsic-elements.explainer.tsx similarity index 100% rename from src/07-types-deep-dive/55-understanding-jsx-intrinsic-elements.explainer.tsx rename to src/07-types-deep-dive/56-understanding-jsx-intrinsic-elements.explainer.tsx diff --git a/src/07-types-deep-dive/56-appending-to-global-namespace.problem.ts b/src/07-types-deep-dive/57-appending-to-global-namespace.problem.ts similarity index 100% rename from src/07-types-deep-dive/56-appending-to-global-namespace.problem.ts rename to src/07-types-deep-dive/57-appending-to-global-namespace.problem.ts diff --git a/src/07-types-deep-dive/56-appending-to-global-namespace.solution.ts b/src/07-types-deep-dive/57-appending-to-global-namespace.solution.ts similarity index 100% rename from src/07-types-deep-dive/56-appending-to-global-namespace.solution.ts rename to src/07-types-deep-dive/57-appending-to-global-namespace.solution.ts diff --git a/src/07-types-deep-dive/57-declaration-merging-in-global-namespace.problem.ts b/src/07-types-deep-dive/58-declaration-merging-in-global-namespace.problem.ts similarity index 100% rename from src/07-types-deep-dive/57-declaration-merging-in-global-namespace.problem.ts rename to src/07-types-deep-dive/58-declaration-merging-in-global-namespace.problem.ts diff --git a/src/07-types-deep-dive/57-declaration-merging-in-global-namespace.solution.ts b/src/07-types-deep-dive/58-declaration-merging-in-global-namespace.solution.ts similarity index 100% rename from src/07-types-deep-dive/57-declaration-merging-in-global-namespace.solution.ts rename to src/07-types-deep-dive/58-declaration-merging-in-global-namespace.solution.ts diff --git a/src/07-types-deep-dive/58-add-new-global-element.problem.tsx b/src/07-types-deep-dive/59-add-new-global-element.problem.tsx similarity index 100% rename from src/07-types-deep-dive/58-add-new-global-element.problem.tsx rename to src/07-types-deep-dive/59-add-new-global-element.problem.tsx diff --git a/src/07-types-deep-dive/58-add-new-global-element.solution.tsx b/src/07-types-deep-dive/59-add-new-global-element.solution.tsx similarity index 100% rename from src/07-types-deep-dive/58-add-new-global-element.solution.tsx rename to src/07-types-deep-dive/59-add-new-global-element.solution.tsx diff --git a/src/07-types-deep-dive/59-html-attributes.explainer.tsx b/src/07-types-deep-dive/60-html-attributes.explainer.tsx similarity index 100% rename from src/07-types-deep-dive/59-html-attributes.explainer.tsx rename to src/07-types-deep-dive/60-html-attributes.explainer.tsx diff --git a/src/07-types-deep-dive/60-add-attribute-to-all-elements.problem.tsx b/src/07-types-deep-dive/61-add-attribute-to-all-elements.problem.tsx similarity index 100% rename from src/07-types-deep-dive/60-add-attribute-to-all-elements.problem.tsx rename to src/07-types-deep-dive/61-add-attribute-to-all-elements.problem.tsx diff --git a/src/07-types-deep-dive/60-add-attribute-to-all-elements.solution.tsx b/src/07-types-deep-dive/61-add-attribute-to-all-elements.solution.tsx similarity index 100% rename from src/07-types-deep-dive/60-add-attribute-to-all-elements.solution.tsx rename to src/07-types-deep-dive/61-add-attribute-to-all-elements.solution.tsx diff --git a/src/08-advanced-patterns/61-lazy-load-component.problem.tsx b/src/08-advanced-patterns/62-lazy-load-component.problem.tsx similarity index 100% rename from src/08-advanced-patterns/61-lazy-load-component.problem.tsx rename to src/08-advanced-patterns/62-lazy-load-component.problem.tsx diff --git a/src/08-advanced-patterns/61-lazy-load-component.solution.tsx b/src/08-advanced-patterns/62-lazy-load-component.solution.tsx similarity index 100% rename from src/08-advanced-patterns/61-lazy-load-component.solution.tsx rename to src/08-advanced-patterns/62-lazy-load-component.solution.tsx diff --git a/src/08-advanced-patterns/62-const-generics-in-generic-components.problem.tsx b/src/08-advanced-patterns/63-const-generics-in-generic-components.problem.tsx similarity index 100% rename from src/08-advanced-patterns/62-const-generics-in-generic-components.problem.tsx rename to src/08-advanced-patterns/63-const-generics-in-generic-components.problem.tsx diff --git a/src/08-advanced-patterns/63-render-props.problem.tsx b/src/08-advanced-patterns/64-render-props.problem.tsx similarity index 100% rename from src/08-advanced-patterns/63-render-props.problem.tsx rename to src/08-advanced-patterns/64-render-props.problem.tsx diff --git a/src/08-advanced-patterns/63-render-props.solution.tsx b/src/08-advanced-patterns/64-render-props.solution.tsx similarity index 100% rename from src/08-advanced-patterns/63-render-props.solution.tsx rename to src/08-advanced-patterns/64-render-props.solution.tsx diff --git a/src/08-advanced-patterns/64-forward-ref-with-generics.explainer.1.tsx b/src/08-advanced-patterns/65-forward-ref-with-generics.explainer.1.tsx similarity index 100% rename from src/08-advanced-patterns/64-forward-ref-with-generics.explainer.1.tsx rename to src/08-advanced-patterns/65-forward-ref-with-generics.explainer.1.tsx diff --git a/src/08-advanced-patterns/64-forward-ref-with-generics.explainer.2.tsx b/src/08-advanced-patterns/65-forward-ref-with-generics.explainer.2.tsx similarity index 100% rename from src/08-advanced-patterns/64-forward-ref-with-generics.explainer.2.tsx rename to src/08-advanced-patterns/65-forward-ref-with-generics.explainer.2.tsx diff --git a/src/08-advanced-patterns/64-forward-ref-with-generics.explainer.3.ts b/src/08-advanced-patterns/65-forward-ref-with-generics.explainer.3.ts similarity index 100% rename from src/08-advanced-patterns/64-forward-ref-with-generics.explainer.3.ts rename to src/08-advanced-patterns/65-forward-ref-with-generics.explainer.3.ts diff --git a/src/08-advanced-patterns/65-forward-ref-as-local-function.problem.tsx b/src/08-advanced-patterns/66-forward-ref-as-local-function.problem.tsx similarity index 100% rename from src/08-advanced-patterns/65-forward-ref-as-local-function.problem.tsx rename to src/08-advanced-patterns/66-forward-ref-as-local-function.problem.tsx diff --git a/src/08-advanced-patterns/65-forward-ref-as-local-function.solution.tsx b/src/08-advanced-patterns/66-forward-ref-as-local-function.solution.tsx similarity index 100% rename from src/08-advanced-patterns/65-forward-ref-as-local-function.solution.tsx rename to src/08-advanced-patterns/66-forward-ref-as-local-function.solution.tsx diff --git a/src/08-advanced-patterns/66-hoc.problem.tsx b/src/08-advanced-patterns/67-hoc.problem.tsx similarity index 100% rename from src/08-advanced-patterns/66-hoc.problem.tsx rename to src/08-advanced-patterns/67-hoc.problem.tsx diff --git a/src/08-advanced-patterns/66-hoc.solution.tsx b/src/08-advanced-patterns/67-hoc.solution.tsx similarity index 100% rename from src/08-advanced-patterns/66-hoc.solution.tsx rename to src/08-advanced-patterns/67-hoc.solution.tsx diff --git a/src/08-advanced-patterns/67-record-of-components-with-same-props.problem.tsx b/src/08-advanced-patterns/68-record-of-components-with-same-props.problem.tsx similarity index 100% rename from src/08-advanced-patterns/67-record-of-components-with-same-props.problem.tsx rename to src/08-advanced-patterns/68-record-of-components-with-same-props.problem.tsx diff --git a/src/08-advanced-patterns/67-record-of-components-with-same-props.solution.1.tsx b/src/08-advanced-patterns/68-record-of-components-with-same-props.solution.1.tsx similarity index 100% rename from src/08-advanced-patterns/67-record-of-components-with-same-props.solution.1.tsx rename to src/08-advanced-patterns/68-record-of-components-with-same-props.solution.1.tsx diff --git a/src/08-advanced-patterns/67-record-of-components-with-same-props.solution.2.tsx b/src/08-advanced-patterns/68-record-of-components-with-same-props.solution.2.tsx similarity index 100% rename from src/08-advanced-patterns/67-record-of-components-with-same-props.solution.2.tsx rename to src/08-advanced-patterns/68-record-of-components-with-same-props.solution.2.tsx diff --git a/src/08-advanced-patterns/68-as-prop.problem.tsx b/src/08-advanced-patterns/69-as-prop.problem.tsx similarity index 100% rename from src/08-advanced-patterns/68-as-prop.problem.tsx rename to src/08-advanced-patterns/69-as-prop.problem.tsx diff --git a/src/08-advanced-patterns/68-as-prop.solution.1.tsx b/src/08-advanced-patterns/69-as-prop.solution.1.tsx similarity index 100% rename from src/08-advanced-patterns/68-as-prop.solution.1.tsx rename to src/08-advanced-patterns/69-as-prop.solution.1.tsx diff --git a/src/08-advanced-patterns/68-as-prop.solution.2.tsx b/src/08-advanced-patterns/69-as-prop.solution.2.tsx similarity index 100% rename from src/08-advanced-patterns/68-as-prop.solution.2.tsx rename to src/08-advanced-patterns/69-as-prop.solution.2.tsx diff --git a/src/08-advanced-patterns/69-as-prop-with-custom-components.problem.tsx b/src/08-advanced-patterns/70-as-prop-with-custom-components.problem.tsx similarity index 100% rename from src/08-advanced-patterns/69-as-prop-with-custom-components.problem.tsx rename to src/08-advanced-patterns/70-as-prop-with-custom-components.problem.tsx diff --git a/src/08-advanced-patterns/69-as-prop-with-custom-components.solution.tsx b/src/08-advanced-patterns/70-as-prop-with-custom-components.solution.tsx similarity index 100% rename from src/08-advanced-patterns/69-as-prop-with-custom-components.solution.tsx rename to src/08-advanced-patterns/70-as-prop-with-custom-components.solution.tsx diff --git a/src/08-advanced-patterns/70-as-prop-with-default.problem.tsx b/src/08-advanced-patterns/71-as-prop-with-default.problem.tsx similarity index 100% rename from src/08-advanced-patterns/70-as-prop-with-default.problem.tsx rename to src/08-advanced-patterns/71-as-prop-with-default.problem.tsx diff --git a/src/08-advanced-patterns/70-as-prop-with-default.solution.tsx b/src/08-advanced-patterns/71-as-prop-with-default.solution.tsx similarity index 100% rename from src/08-advanced-patterns/70-as-prop-with-default.solution.tsx rename to src/08-advanced-patterns/71-as-prop-with-default.solution.tsx diff --git a/src/09-external-libraries/71-react-hook-form.explainer.tsx b/src/09-external-libraries/72-react-hook-form.explainer.tsx similarity index 100% rename from src/09-external-libraries/71-react-hook-form.explainer.tsx rename to src/09-external-libraries/72-react-hook-form.explainer.tsx diff --git a/src/09-external-libraries/72-react-hook-form-wrapper.problem.tsx b/src/09-external-libraries/73-react-hook-form-wrapper.problem.tsx similarity index 100% rename from src/09-external-libraries/72-react-hook-form-wrapper.problem.tsx rename to src/09-external-libraries/73-react-hook-form-wrapper.problem.tsx diff --git a/src/09-external-libraries/72-react-hook-form-wrapper.solution.tsx b/src/09-external-libraries/73-react-hook-form-wrapper.solution.tsx similarity index 100% rename from src/09-external-libraries/72-react-hook-form-wrapper.solution.tsx rename to src/09-external-libraries/73-react-hook-form-wrapper.solution.tsx diff --git a/src/09-external-libraries/73-react-select.problem.tsx b/src/09-external-libraries/74-react-select.problem.tsx similarity index 100% rename from src/09-external-libraries/73-react-select.problem.tsx rename to src/09-external-libraries/74-react-select.problem.tsx diff --git a/src/09-external-libraries/73-react-select.solution.tsx b/src/09-external-libraries/74-react-select.solution.tsx similarity index 100% rename from src/09-external-libraries/73-react-select.solution.tsx rename to src/09-external-libraries/74-react-select.solution.tsx diff --git a/src/09-external-libraries/74-react-query.explainer.ts b/src/09-external-libraries/75-react-query.explainer.ts similarity index 100% rename from src/09-external-libraries/74-react-query.explainer.ts rename to src/09-external-libraries/75-react-query.explainer.ts diff --git a/src/09-external-libraries/75-react-query-wrapper.problem.ts b/src/09-external-libraries/76-react-query-wrapper.problem.ts similarity index 100% rename from src/09-external-libraries/75-react-query-wrapper.problem.ts rename to src/09-external-libraries/76-react-query-wrapper.problem.ts diff --git a/src/09-external-libraries/75-react-query-wrapper.solution.ts b/src/09-external-libraries/76-react-query-wrapper.solution.ts similarity index 100% rename from src/09-external-libraries/75-react-query-wrapper.solution.ts rename to src/09-external-libraries/76-react-query-wrapper.solution.ts From 3208fb90cd84c7d52ad4877d8e314e48ad39ef63 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 10 Jul 2023 12:26:34 +0100 Subject: [PATCH 003/105] Changed 47 example --- .../47-discriminated-unions-in-usestate.problem.tsx | 13 +++++++++++++ ...47-discriminated-unions-in-usestate.solution.tsx | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/06-advanced-hooks/47-discriminated-unions-in-usestate.problem.tsx b/src/06-advanced-hooks/47-discriminated-unions-in-usestate.problem.tsx index 1526d53..184ff7e 100644 --- a/src/06-advanced-hooks/47-discriminated-unions-in-usestate.problem.tsx +++ b/src/06-advanced-hooks/47-discriminated-unions-in-usestate.problem.tsx @@ -30,15 +30,28 @@ export const useLoadAsyncVideo = (src: string) => { useEffect(() => { setState({ status: "loading" }); + let cancelled = false; + fetchVideo(src) .then((blob) => { + if (cancelled) { + return; + } + appendVideoToDomAndPlay(blob); setState({ status: "loaded" }); }) .catch((error) => { + if (cancelled) { + return; + } setState({ status: "error", error }); }); + + return () => { + cancelled = true; + }; }, [src]); // @ts-expect-error diff --git a/src/06-advanced-hooks/47-discriminated-unions-in-usestate.solution.tsx b/src/06-advanced-hooks/47-discriminated-unions-in-usestate.solution.tsx index b9a2f10..3cbd4eb 100644 --- a/src/06-advanced-hooks/47-discriminated-unions-in-usestate.solution.tsx +++ b/src/06-advanced-hooks/47-discriminated-unions-in-usestate.solution.tsx @@ -21,15 +21,28 @@ export const useLoadAsyncVideo = (src: string) => { useEffect(() => { setState({ status: "loading" }); + let cancelled = false; + fetchVideo(src) .then((blob) => { + if (cancelled) { + return; + } + appendVideoToDomAndPlay(blob); setState({ status: "loaded" }); }) .catch((error) => { + if (cancelled) { + return; + } setState({ status: "error", error }); }); + + return () => { + cancelled = true; + }; }, [src]); // @ts-expect-error From 47a57c8a45888e19d8944279bd0360834ea45262 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 10 Jul 2023 12:28:10 +0100 Subject: [PATCH 004/105] Changed 47 setup --- ...scriminated-unions-in-usestate.problem.tsx | 27 ++++--------------- ...criminated-unions-in-usestate.solution.tsx | 4 +++ 2 files changed, 9 insertions(+), 22 deletions(-) diff --git a/src/06-advanced-hooks/47-discriminated-unions-in-usestate.problem.tsx b/src/06-advanced-hooks/47-discriminated-unions-in-usestate.problem.tsx index 184ff7e..9d36f1e 100644 --- a/src/06-advanced-hooks/47-discriminated-unions-in-usestate.problem.tsx +++ b/src/06-advanced-hooks/47-discriminated-unions-in-usestate.problem.tsx @@ -1,29 +1,8 @@ import { appendVideoToDomAndPlay, fetchVideo } from "fake-external-lib"; import { useEffect, useState } from "react"; -/** - * Here, we're doing the same trick as before - using a state - * variable to track the status of the video loading. - * - * But this time, we're storing it an object, with an extra - * property for the error. - * - * This could be improved - we should only be allowed to specify - * the error property when the status is "error". - * - * 1. Change the State interface so that the error property is only - * allowed when the status is "error". - */ - -type Status = "loading" | "loaded" | "error"; - -interface State { - status: Status; - error?: Error; -} - export const useLoadAsyncVideo = (src: string) => { - const [state, setState] = useState({ + const [state, setState] = useState({ status: "loading", }); @@ -62,4 +41,8 @@ export const useLoadAsyncVideo = (src: string) => { // @ts-expect-error setState({ status: "loaded", error: new Error("error") }); + + if (state.status === "error") { + console.error(state.error); + } }; diff --git a/src/06-advanced-hooks/47-discriminated-unions-in-usestate.solution.tsx b/src/06-advanced-hooks/47-discriminated-unions-in-usestate.solution.tsx index 3cbd4eb..c1ac30b 100644 --- a/src/06-advanced-hooks/47-discriminated-unions-in-usestate.solution.tsx +++ b/src/06-advanced-hooks/47-discriminated-unions-in-usestate.solution.tsx @@ -53,4 +53,8 @@ export const useLoadAsyncVideo = (src: string) => { // @ts-expect-error setState({ status: "loaded", error: new Error("error") }); + + if (state.status === "error") { + console.error(state.error); + } }; From 21404ed68336285d977582cd44dc992c3e8ce220 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 10 Jul 2023 13:01:42 +0100 Subject: [PATCH 005/105] Changed 47 --- .../47-discriminated-unions-in-usestate.solution.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/06-advanced-hooks/47-discriminated-unions-in-usestate.solution.tsx b/src/06-advanced-hooks/47-discriminated-unions-in-usestate.solution.tsx index c1ac30b..45b8477 100644 --- a/src/06-advanced-hooks/47-discriminated-unions-in-usestate.solution.tsx +++ b/src/06-advanced-hooks/47-discriminated-unions-in-usestate.solution.tsx @@ -3,10 +3,7 @@ import { useEffect, useState } from "react"; type State = | { - status: "loading"; - } - | { - status: "loaded"; + status: "loading" | "loaded"; } | { status: "error"; From aa09e15e4ff48678421479a3b430b39e47077e89 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 10 Jul 2023 13:07:06 +0100 Subject: [PATCH 006/105] Changed 48 success --- ...discriminated-tuples-from-custom-hooks.solution.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/06-advanced-hooks/48-discriminated-tuples-from-custom-hooks.solution.tsx b/src/06-advanced-hooks/48-discriminated-tuples-from-custom-hooks.solution.tsx index dcf7160..b1661c1 100644 --- a/src/06-advanced-hooks/48-discriminated-tuples-from-custom-hooks.solution.tsx +++ b/src/06-advanced-hooks/48-discriminated-tuples-from-custom-hooks.solution.tsx @@ -7,12 +7,12 @@ import { useEffect, useState } from "react"; * even after it's been destructured. */ export type Result = - | ["loading", undefined] - | ["error", Error] - | ["success", T]; + | ["loading", undefined?] + | ["success", T] + | ["error", Error]; export const useData = (url: string): Result => { - const [result, setResult] = useState>(["loading", undefined]); + const [result, setResult] = useState>(["loading"]); useEffect(() => { fetch(url) @@ -26,7 +26,7 @@ export const useData = (url: string): Result => { const Component = () => { const [status, value] = useData<{ title: string }>( - "https://jsonplaceholder.typicode.com/todos/1", + "https://jsonplaceholder.typicode.com/todos/1" ); if (status === "loading") { From 66891d8f4a4a04cf2a4d6bfc561cc8fc30975266 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 10 Jul 2023 13:15:46 +0100 Subject: [PATCH 007/105] Changed 49 --- src/06-advanced-hooks/49-use-state-overloads.solution.1.ts | 2 +- src/06-advanced-hooks/49-use-state-overloads.solution.2.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/06-advanced-hooks/49-use-state-overloads.solution.1.ts b/src/06-advanced-hooks/49-use-state-overloads.solution.1.ts index 90ab8bf..7723958 100644 --- a/src/06-advanced-hooks/49-use-state-overloads.solution.1.ts +++ b/src/06-advanced-hooks/49-use-state-overloads.solution.1.ts @@ -17,5 +17,5 @@ const example2 = maybeReturnsString(); type tests = [ Expect>, - Expect>, + Expect> ]; diff --git a/src/06-advanced-hooks/49-use-state-overloads.solution.2.ts b/src/06-advanced-hooks/49-use-state-overloads.solution.2.ts index 107f774..9d1e63e 100644 --- a/src/06-advanced-hooks/49-use-state-overloads.solution.2.ts +++ b/src/06-advanced-hooks/49-use-state-overloads.solution.2.ts @@ -7,7 +7,7 @@ import { Equal, Expect } from "../helpers/type-utils"; function maybeReturnsString(defaultString: string): string; function maybeReturnsString( - defaultString?: string | undefined, + defaultString?: string | undefined ): string | undefined; function maybeReturnsString(defaultString?: string) { // If you pass a string, it always returns a string @@ -20,9 +20,9 @@ function maybeReturnsString(defaultString?: string) { } const example1 = maybeReturnsString("hello"); -const example2 = maybeReturnsString(); +const example2 = maybeReturnsString(undefined); type tests = [ Expect>, - Expect>, + Expect> ]; From 7c8a571a3f33a31daa2f1ff4ae7f28c54eb313c1 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 10 Jul 2023 13:41:47 +0100 Subject: [PATCH 008/105] Moved required context around --- ...quired-context.problem.tsx => 46-required-context.problem.tsx} | 0 ...-context.solution.1.tsx => 46-required-context.solution.1.tsx} | 0 ...-context.solution.2.tsx => 46-required-context.solution.2.tsx} | 0 ...-in-usestate.problem.tsx => 47-unions-in-usestate.problem.tsx} | 0 ...n-usestate.solution.tsx => 47-unions-in-usestate.solution.tsx} | 0 ...roblem.tsx => 48-discriminated-unions-in-usestate.problem.tsx} | 0 ...ution.tsx => 48-discriminated-unions-in-usestate.solution.tsx} | 0 ....tsx => 49-discriminated-tuples-from-custom-hooks.problem.tsx} | 0 ...tsx => 49-discriminated-tuples-from-custom-hooks.solution.tsx} | 0 ...ate-overloads.problem.ts => 50-use-state-overloads.problem.ts} | 0 ...erloads.solution.1.ts => 50-use-state-overloads.solution.1.ts} | 0 ...erloads.solution.2.ts => 50-use-state-overloads.solution.2.ts} | 0 ...hooks.problem.ts => 51-function-overloads-in-hooks.problem.ts} | 0 ...solution.1.ts => 51-function-overloads-in-hooks.solution.1.ts} | 0 ...solution.2.ts => 51-function-overloads-in-hooks.solution.2.ts} | 0 ...{51-currying-hooks.problem.ts => 52-currying-hooks.problem.ts} | 0 ...1-currying-hooks.solution.ts => 52-currying-hooks.solution.ts} | 0 17 files changed, 0 insertions(+), 0 deletions(-) rename src/06-advanced-hooks/{52-required-context.problem.tsx => 46-required-context.problem.tsx} (100%) rename src/06-advanced-hooks/{52-required-context.solution.1.tsx => 46-required-context.solution.1.tsx} (100%) rename src/06-advanced-hooks/{52-required-context.solution.2.tsx => 46-required-context.solution.2.tsx} (100%) rename src/06-advanced-hooks/{46-unions-in-usestate.problem.tsx => 47-unions-in-usestate.problem.tsx} (100%) rename src/06-advanced-hooks/{46-unions-in-usestate.solution.tsx => 47-unions-in-usestate.solution.tsx} (100%) rename src/06-advanced-hooks/{47-discriminated-unions-in-usestate.problem.tsx => 48-discriminated-unions-in-usestate.problem.tsx} (100%) rename src/06-advanced-hooks/{47-discriminated-unions-in-usestate.solution.tsx => 48-discriminated-unions-in-usestate.solution.tsx} (100%) rename src/06-advanced-hooks/{48-discriminated-tuples-from-custom-hooks.problem.tsx => 49-discriminated-tuples-from-custom-hooks.problem.tsx} (100%) rename src/06-advanced-hooks/{48-discriminated-tuples-from-custom-hooks.solution.tsx => 49-discriminated-tuples-from-custom-hooks.solution.tsx} (100%) rename src/06-advanced-hooks/{49-use-state-overloads.problem.ts => 50-use-state-overloads.problem.ts} (100%) rename src/06-advanced-hooks/{49-use-state-overloads.solution.1.ts => 50-use-state-overloads.solution.1.ts} (100%) rename src/06-advanced-hooks/{49-use-state-overloads.solution.2.ts => 50-use-state-overloads.solution.2.ts} (100%) rename src/06-advanced-hooks/{50-function-overloads-in-hooks.problem.ts => 51-function-overloads-in-hooks.problem.ts} (100%) rename src/06-advanced-hooks/{50-function-overloads-in-hooks.solution.1.ts => 51-function-overloads-in-hooks.solution.1.ts} (100%) rename src/06-advanced-hooks/{50-function-overloads-in-hooks.solution.2.ts => 51-function-overloads-in-hooks.solution.2.ts} (100%) rename src/06-advanced-hooks/{51-currying-hooks.problem.ts => 52-currying-hooks.problem.ts} (100%) rename src/06-advanced-hooks/{51-currying-hooks.solution.ts => 52-currying-hooks.solution.ts} (100%) diff --git a/src/06-advanced-hooks/52-required-context.problem.tsx b/src/06-advanced-hooks/46-required-context.problem.tsx similarity index 100% rename from src/06-advanced-hooks/52-required-context.problem.tsx rename to src/06-advanced-hooks/46-required-context.problem.tsx diff --git a/src/06-advanced-hooks/52-required-context.solution.1.tsx b/src/06-advanced-hooks/46-required-context.solution.1.tsx similarity index 100% rename from src/06-advanced-hooks/52-required-context.solution.1.tsx rename to src/06-advanced-hooks/46-required-context.solution.1.tsx diff --git a/src/06-advanced-hooks/52-required-context.solution.2.tsx b/src/06-advanced-hooks/46-required-context.solution.2.tsx similarity index 100% rename from src/06-advanced-hooks/52-required-context.solution.2.tsx rename to src/06-advanced-hooks/46-required-context.solution.2.tsx diff --git a/src/06-advanced-hooks/46-unions-in-usestate.problem.tsx b/src/06-advanced-hooks/47-unions-in-usestate.problem.tsx similarity index 100% rename from src/06-advanced-hooks/46-unions-in-usestate.problem.tsx rename to src/06-advanced-hooks/47-unions-in-usestate.problem.tsx diff --git a/src/06-advanced-hooks/46-unions-in-usestate.solution.tsx b/src/06-advanced-hooks/47-unions-in-usestate.solution.tsx similarity index 100% rename from src/06-advanced-hooks/46-unions-in-usestate.solution.tsx rename to src/06-advanced-hooks/47-unions-in-usestate.solution.tsx diff --git a/src/06-advanced-hooks/47-discriminated-unions-in-usestate.problem.tsx b/src/06-advanced-hooks/48-discriminated-unions-in-usestate.problem.tsx similarity index 100% rename from src/06-advanced-hooks/47-discriminated-unions-in-usestate.problem.tsx rename to src/06-advanced-hooks/48-discriminated-unions-in-usestate.problem.tsx diff --git a/src/06-advanced-hooks/47-discriminated-unions-in-usestate.solution.tsx b/src/06-advanced-hooks/48-discriminated-unions-in-usestate.solution.tsx similarity index 100% rename from src/06-advanced-hooks/47-discriminated-unions-in-usestate.solution.tsx rename to src/06-advanced-hooks/48-discriminated-unions-in-usestate.solution.tsx diff --git a/src/06-advanced-hooks/48-discriminated-tuples-from-custom-hooks.problem.tsx b/src/06-advanced-hooks/49-discriminated-tuples-from-custom-hooks.problem.tsx similarity index 100% rename from src/06-advanced-hooks/48-discriminated-tuples-from-custom-hooks.problem.tsx rename to src/06-advanced-hooks/49-discriminated-tuples-from-custom-hooks.problem.tsx diff --git a/src/06-advanced-hooks/48-discriminated-tuples-from-custom-hooks.solution.tsx b/src/06-advanced-hooks/49-discriminated-tuples-from-custom-hooks.solution.tsx similarity index 100% rename from src/06-advanced-hooks/48-discriminated-tuples-from-custom-hooks.solution.tsx rename to src/06-advanced-hooks/49-discriminated-tuples-from-custom-hooks.solution.tsx diff --git a/src/06-advanced-hooks/49-use-state-overloads.problem.ts b/src/06-advanced-hooks/50-use-state-overloads.problem.ts similarity index 100% rename from src/06-advanced-hooks/49-use-state-overloads.problem.ts rename to src/06-advanced-hooks/50-use-state-overloads.problem.ts diff --git a/src/06-advanced-hooks/49-use-state-overloads.solution.1.ts b/src/06-advanced-hooks/50-use-state-overloads.solution.1.ts similarity index 100% rename from src/06-advanced-hooks/49-use-state-overloads.solution.1.ts rename to src/06-advanced-hooks/50-use-state-overloads.solution.1.ts diff --git a/src/06-advanced-hooks/49-use-state-overloads.solution.2.ts b/src/06-advanced-hooks/50-use-state-overloads.solution.2.ts similarity index 100% rename from src/06-advanced-hooks/49-use-state-overloads.solution.2.ts rename to src/06-advanced-hooks/50-use-state-overloads.solution.2.ts diff --git a/src/06-advanced-hooks/50-function-overloads-in-hooks.problem.ts b/src/06-advanced-hooks/51-function-overloads-in-hooks.problem.ts similarity index 100% rename from src/06-advanced-hooks/50-function-overloads-in-hooks.problem.ts rename to src/06-advanced-hooks/51-function-overloads-in-hooks.problem.ts diff --git a/src/06-advanced-hooks/50-function-overloads-in-hooks.solution.1.ts b/src/06-advanced-hooks/51-function-overloads-in-hooks.solution.1.ts similarity index 100% rename from src/06-advanced-hooks/50-function-overloads-in-hooks.solution.1.ts rename to src/06-advanced-hooks/51-function-overloads-in-hooks.solution.1.ts diff --git a/src/06-advanced-hooks/50-function-overloads-in-hooks.solution.2.ts b/src/06-advanced-hooks/51-function-overloads-in-hooks.solution.2.ts similarity index 100% rename from src/06-advanced-hooks/50-function-overloads-in-hooks.solution.2.ts rename to src/06-advanced-hooks/51-function-overloads-in-hooks.solution.2.ts diff --git a/src/06-advanced-hooks/51-currying-hooks.problem.ts b/src/06-advanced-hooks/52-currying-hooks.problem.ts similarity index 100% rename from src/06-advanced-hooks/51-currying-hooks.problem.ts rename to src/06-advanced-hooks/52-currying-hooks.problem.ts diff --git a/src/06-advanced-hooks/51-currying-hooks.solution.ts b/src/06-advanced-hooks/52-currying-hooks.solution.ts similarity index 100% rename from src/06-advanced-hooks/51-currying-hooks.solution.ts rename to src/06-advanced-hooks/52-currying-hooks.solution.ts From 25c22cdfcc5c1f8e3c16af85c8189a3d903babd2 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Tue, 11 Jul 2023 17:42:42 +0100 Subject: [PATCH 009/105] Possible 56.5 example --- package.json | 8 +++- .../56.5-react-component-type.explainer.tsx | 47 +++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 src/07-types-deep-dive/56.5-react-component-type.explainer.tsx diff --git a/package.json b/package.json index 467b6b2..549cd36 100644 --- a/package.json +++ b/package.json @@ -156,7 +156,13 @@ "e-71": "tt-cli run 71", "s-71": "tt-cli run 71 --solution", "e-73": "tt-cli run 73", - "s-73": "tt-cli run 73 --solution" + "s-73": "tt-cli run 73 --solution", + "e-69": "tt-cli run 69", + "s-69": "tt-cli run 69 --solution", + "e-74": "tt-cli run 74", + "s-74": "tt-cli run 74 --solution", + "e-76": "tt-cli run 76", + "s-76": "tt-cli run 76 --solution" }, "dependencies": { "@tanstack/react-query": "^4.29.12", diff --git a/src/07-types-deep-dive/56.5-react-component-type.explainer.tsx b/src/07-types-deep-dive/56.5-react-component-type.explainer.tsx new file mode 100644 index 0000000..f099499 --- /dev/null +++ b/src/07-types-deep-dive/56.5-react-component-type.explainer.tsx @@ -0,0 +1,47 @@ +type types = [ + React.ElementType, + React.ComponentType, + React.JSXElementConstructor<{ + prop1: string; + }> +]; + +/** + * ElementType + * + * Lets you specify certain types of elements + * which can receive those props. + * + * For instance, Example accepts 'audio' and 'video'! + * As well as ComponentType

+ */ +export type Example = React.ElementType<{ + autoPlay?: boolean; +}>; + +/** + * JSXElementConstructor + */ +const Example1 = (props: { prop1: string }) => { + return null; +}; + +class Example2 extends React.Component<{ + prop1: string; +}> { + render(): React.ReactNode { + this.props.prop1; + return null; + } +} + +const tests: Array< + React.JSXElementConstructor<{ + prop1: string; + }> +> = [Example1, Example2]; + +const tests2: Array> = [ + Example1, + Example2, +]; From 718bf10f4dc7e389c115c40a5c813c2c441a659e Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 17 Jul 2023 10:45:31 +0100 Subject: [PATCH 010/105] Adjusted 56.5 --- .../56.5-react-component-type.explainer.tsx | 24 +++++-------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/src/07-types-deep-dive/56.5-react-component-type.explainer.tsx b/src/07-types-deep-dive/56.5-react-component-type.explainer.tsx index f099499..ab99ef4 100644 --- a/src/07-types-deep-dive/56.5-react-component-type.explainer.tsx +++ b/src/07-types-deep-dive/56.5-react-component-type.explainer.tsx @@ -1,10 +1,4 @@ -type types = [ - React.ElementType, - React.ComponentType, - React.JSXElementConstructor<{ - prop1: string; - }> -]; +type types = [React.ElementType, React.ComponentType]; /** * ElementType @@ -20,13 +14,13 @@ export type Example = React.ElementType<{ }>; /** - * JSXElementConstructor + * ComponentType */ -const Example1 = (props: { prop1: string }) => { +const FuncComponent = (props: { prop1: string }) => { return null; }; -class Example2 extends React.Component<{ +class ClassComponent extends React.Component<{ prop1: string; }> { render(): React.ReactNode { @@ -35,13 +29,7 @@ class Example2 extends React.Component<{ } } -const tests: Array< - React.JSXElementConstructor<{ - prop1: string; - }> -> = [Example1, Example2]; - const tests2: Array> = [ - Example1, - Example2, + FuncComponent, + ClassComponent, ]; From 54d908d7ee22daac6d3d86895397a4395d8bf101 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 17 Jul 2023 10:45:59 +0100 Subject: [PATCH 011/105] Reorder --- ...t-type.explainer.tsx => 57-react-component-type.explainer.tsx} | 0 ...ace.problem.ts => 58-appending-to-global-namespace.problem.ts} | 0 ...e.solution.ts => 58-appending-to-global-namespace.solution.ts} | 0 ...m.ts => 59-declaration-merging-in-global-namespace.problem.ts} | 0 ....ts => 59-declaration-merging-in-global-namespace.solution.ts} | 0 ...-element.problem.tsx => 60-add-new-global-element.problem.tsx} | 0 ...lement.solution.tsx => 60-add-new-global-element.solution.tsx} | 0 ...-attributes.explainer.tsx => 61-html-attributes.explainer.tsx} | 0 ...s.problem.tsx => 62-add-attribute-to-all-elements.problem.tsx} | 0 ...solution.tsx => 62-add-attribute-to-all-elements.solution.tsx} | 0 ...d-component.problem.tsx => 63-lazy-load-component.problem.tsx} | 0 ...component.solution.tsx => 63-lazy-load-component.solution.tsx} | 0 ...em.tsx => 64-const-generics-in-generic-components.problem.tsx} | 0 .../{64-render-props.problem.tsx => 65-render-props.problem.tsx} | 0 ...{64-render-props.solution.tsx => 65-render-props.solution.tsx} | 0 ...plainer.1.tsx => 66-forward-ref-with-generics.explainer.1.tsx} | 0 ...plainer.2.tsx => 66-forward-ref-with-generics.explainer.2.tsx} | 0 ...explainer.3.ts => 66-forward-ref-with-generics.explainer.3.ts} | 0 ...n.problem.tsx => 67-forward-ref-as-local-function.problem.tsx} | 0 ...solution.tsx => 67-forward-ref-as-local-function.solution.tsx} | 0 .../{67-hoc.problem.tsx => 68-hoc.problem.tsx} | 0 .../{67-hoc.solution.tsx => 68-hoc.solution.tsx} | 0 ...em.tsx => 69-record-of-components-with-same-props.problem.tsx} | 0 ...tsx => 69-record-of-components-with-same-props.solution.1.tsx} | 0 ...tsx => 69-record-of-components-with-same-props.solution.2.tsx} | 0 .../{69-as-prop.problem.tsx => 70-as-prop.problem.tsx} | 0 .../{69-as-prop.solution.1.tsx => 70-as-prop.solution.1.tsx} | 0 .../{69-as-prop.solution.2.tsx => 70-as-prop.solution.2.tsx} | 0 ....problem.tsx => 71-as-prop-with-custom-components.problem.tsx} | 0 ...olution.tsx => 71-as-prop-with-custom-components.solution.tsx} | 0 ...th-default.problem.tsx => 72-as-prop-with-default.problem.tsx} | 0 ...-default.solution.tsx => 72-as-prop-with-default.solution.tsx} | 0 ...t-hook-form.explainer.tsx => 73-react-hook-form.explainer.tsx} | 0 ...wrapper.problem.tsx => 74-react-hook-form-wrapper.problem.tsx} | 0 ...apper.solution.tsx => 74-react-hook-form-wrapper.solution.tsx} | 0 .../{74-react-select.problem.tsx => 75-react-select.problem.tsx} | 0 ...{74-react-select.solution.tsx => 75-react-select.solution.tsx} | 0 .../{75-react-query.explainer.ts => 76-react-query.explainer.ts} | 0 ...query-wrapper.problem.ts => 77-react-query-wrapper.problem.ts} | 0 ...ery-wrapper.solution.ts => 77-react-query-wrapper.solution.ts} | 0 40 files changed, 0 insertions(+), 0 deletions(-) rename src/07-types-deep-dive/{56.5-react-component-type.explainer.tsx => 57-react-component-type.explainer.tsx} (100%) rename src/07-types-deep-dive/{57-appending-to-global-namespace.problem.ts => 58-appending-to-global-namespace.problem.ts} (100%) rename src/07-types-deep-dive/{57-appending-to-global-namespace.solution.ts => 58-appending-to-global-namespace.solution.ts} (100%) rename src/07-types-deep-dive/{58-declaration-merging-in-global-namespace.problem.ts => 59-declaration-merging-in-global-namespace.problem.ts} (100%) rename src/07-types-deep-dive/{58-declaration-merging-in-global-namespace.solution.ts => 59-declaration-merging-in-global-namespace.solution.ts} (100%) rename src/07-types-deep-dive/{59-add-new-global-element.problem.tsx => 60-add-new-global-element.problem.tsx} (100%) rename src/07-types-deep-dive/{59-add-new-global-element.solution.tsx => 60-add-new-global-element.solution.tsx} (100%) rename src/07-types-deep-dive/{60-html-attributes.explainer.tsx => 61-html-attributes.explainer.tsx} (100%) rename src/07-types-deep-dive/{61-add-attribute-to-all-elements.problem.tsx => 62-add-attribute-to-all-elements.problem.tsx} (100%) rename src/07-types-deep-dive/{61-add-attribute-to-all-elements.solution.tsx => 62-add-attribute-to-all-elements.solution.tsx} (100%) rename src/08-advanced-patterns/{62-lazy-load-component.problem.tsx => 63-lazy-load-component.problem.tsx} (100%) rename src/08-advanced-patterns/{62-lazy-load-component.solution.tsx => 63-lazy-load-component.solution.tsx} (100%) rename src/08-advanced-patterns/{63-const-generics-in-generic-components.problem.tsx => 64-const-generics-in-generic-components.problem.tsx} (100%) rename src/08-advanced-patterns/{64-render-props.problem.tsx => 65-render-props.problem.tsx} (100%) rename src/08-advanced-patterns/{64-render-props.solution.tsx => 65-render-props.solution.tsx} (100%) rename src/08-advanced-patterns/{65-forward-ref-with-generics.explainer.1.tsx => 66-forward-ref-with-generics.explainer.1.tsx} (100%) rename src/08-advanced-patterns/{65-forward-ref-with-generics.explainer.2.tsx => 66-forward-ref-with-generics.explainer.2.tsx} (100%) rename src/08-advanced-patterns/{65-forward-ref-with-generics.explainer.3.ts => 66-forward-ref-with-generics.explainer.3.ts} (100%) rename src/08-advanced-patterns/{66-forward-ref-as-local-function.problem.tsx => 67-forward-ref-as-local-function.problem.tsx} (100%) rename src/08-advanced-patterns/{66-forward-ref-as-local-function.solution.tsx => 67-forward-ref-as-local-function.solution.tsx} (100%) rename src/08-advanced-patterns/{67-hoc.problem.tsx => 68-hoc.problem.tsx} (100%) rename src/08-advanced-patterns/{67-hoc.solution.tsx => 68-hoc.solution.tsx} (100%) rename src/08-advanced-patterns/{68-record-of-components-with-same-props.problem.tsx => 69-record-of-components-with-same-props.problem.tsx} (100%) rename src/08-advanced-patterns/{68-record-of-components-with-same-props.solution.1.tsx => 69-record-of-components-with-same-props.solution.1.tsx} (100%) rename src/08-advanced-patterns/{68-record-of-components-with-same-props.solution.2.tsx => 69-record-of-components-with-same-props.solution.2.tsx} (100%) rename src/08-advanced-patterns/{69-as-prop.problem.tsx => 70-as-prop.problem.tsx} (100%) rename src/08-advanced-patterns/{69-as-prop.solution.1.tsx => 70-as-prop.solution.1.tsx} (100%) rename src/08-advanced-patterns/{69-as-prop.solution.2.tsx => 70-as-prop.solution.2.tsx} (100%) rename src/08-advanced-patterns/{70-as-prop-with-custom-components.problem.tsx => 71-as-prop-with-custom-components.problem.tsx} (100%) rename src/08-advanced-patterns/{70-as-prop-with-custom-components.solution.tsx => 71-as-prop-with-custom-components.solution.tsx} (100%) rename src/08-advanced-patterns/{71-as-prop-with-default.problem.tsx => 72-as-prop-with-default.problem.tsx} (100%) rename src/08-advanced-patterns/{71-as-prop-with-default.solution.tsx => 72-as-prop-with-default.solution.tsx} (100%) rename src/09-external-libraries/{72-react-hook-form.explainer.tsx => 73-react-hook-form.explainer.tsx} (100%) rename src/09-external-libraries/{73-react-hook-form-wrapper.problem.tsx => 74-react-hook-form-wrapper.problem.tsx} (100%) rename src/09-external-libraries/{73-react-hook-form-wrapper.solution.tsx => 74-react-hook-form-wrapper.solution.tsx} (100%) rename src/09-external-libraries/{74-react-select.problem.tsx => 75-react-select.problem.tsx} (100%) rename src/09-external-libraries/{74-react-select.solution.tsx => 75-react-select.solution.tsx} (100%) rename src/09-external-libraries/{75-react-query.explainer.ts => 76-react-query.explainer.ts} (100%) rename src/09-external-libraries/{76-react-query-wrapper.problem.ts => 77-react-query-wrapper.problem.ts} (100%) rename src/09-external-libraries/{76-react-query-wrapper.solution.ts => 77-react-query-wrapper.solution.ts} (100%) diff --git a/src/07-types-deep-dive/56.5-react-component-type.explainer.tsx b/src/07-types-deep-dive/57-react-component-type.explainer.tsx similarity index 100% rename from src/07-types-deep-dive/56.5-react-component-type.explainer.tsx rename to src/07-types-deep-dive/57-react-component-type.explainer.tsx diff --git a/src/07-types-deep-dive/57-appending-to-global-namespace.problem.ts b/src/07-types-deep-dive/58-appending-to-global-namespace.problem.ts similarity index 100% rename from src/07-types-deep-dive/57-appending-to-global-namespace.problem.ts rename to src/07-types-deep-dive/58-appending-to-global-namespace.problem.ts diff --git a/src/07-types-deep-dive/57-appending-to-global-namespace.solution.ts b/src/07-types-deep-dive/58-appending-to-global-namespace.solution.ts similarity index 100% rename from src/07-types-deep-dive/57-appending-to-global-namespace.solution.ts rename to src/07-types-deep-dive/58-appending-to-global-namespace.solution.ts diff --git a/src/07-types-deep-dive/58-declaration-merging-in-global-namespace.problem.ts b/src/07-types-deep-dive/59-declaration-merging-in-global-namespace.problem.ts similarity index 100% rename from src/07-types-deep-dive/58-declaration-merging-in-global-namespace.problem.ts rename to src/07-types-deep-dive/59-declaration-merging-in-global-namespace.problem.ts diff --git a/src/07-types-deep-dive/58-declaration-merging-in-global-namespace.solution.ts b/src/07-types-deep-dive/59-declaration-merging-in-global-namespace.solution.ts similarity index 100% rename from src/07-types-deep-dive/58-declaration-merging-in-global-namespace.solution.ts rename to src/07-types-deep-dive/59-declaration-merging-in-global-namespace.solution.ts diff --git a/src/07-types-deep-dive/59-add-new-global-element.problem.tsx b/src/07-types-deep-dive/60-add-new-global-element.problem.tsx similarity index 100% rename from src/07-types-deep-dive/59-add-new-global-element.problem.tsx rename to src/07-types-deep-dive/60-add-new-global-element.problem.tsx diff --git a/src/07-types-deep-dive/59-add-new-global-element.solution.tsx b/src/07-types-deep-dive/60-add-new-global-element.solution.tsx similarity index 100% rename from src/07-types-deep-dive/59-add-new-global-element.solution.tsx rename to src/07-types-deep-dive/60-add-new-global-element.solution.tsx diff --git a/src/07-types-deep-dive/60-html-attributes.explainer.tsx b/src/07-types-deep-dive/61-html-attributes.explainer.tsx similarity index 100% rename from src/07-types-deep-dive/60-html-attributes.explainer.tsx rename to src/07-types-deep-dive/61-html-attributes.explainer.tsx diff --git a/src/07-types-deep-dive/61-add-attribute-to-all-elements.problem.tsx b/src/07-types-deep-dive/62-add-attribute-to-all-elements.problem.tsx similarity index 100% rename from src/07-types-deep-dive/61-add-attribute-to-all-elements.problem.tsx rename to src/07-types-deep-dive/62-add-attribute-to-all-elements.problem.tsx diff --git a/src/07-types-deep-dive/61-add-attribute-to-all-elements.solution.tsx b/src/07-types-deep-dive/62-add-attribute-to-all-elements.solution.tsx similarity index 100% rename from src/07-types-deep-dive/61-add-attribute-to-all-elements.solution.tsx rename to src/07-types-deep-dive/62-add-attribute-to-all-elements.solution.tsx diff --git a/src/08-advanced-patterns/62-lazy-load-component.problem.tsx b/src/08-advanced-patterns/63-lazy-load-component.problem.tsx similarity index 100% rename from src/08-advanced-patterns/62-lazy-load-component.problem.tsx rename to src/08-advanced-patterns/63-lazy-load-component.problem.tsx diff --git a/src/08-advanced-patterns/62-lazy-load-component.solution.tsx b/src/08-advanced-patterns/63-lazy-load-component.solution.tsx similarity index 100% rename from src/08-advanced-patterns/62-lazy-load-component.solution.tsx rename to src/08-advanced-patterns/63-lazy-load-component.solution.tsx diff --git a/src/08-advanced-patterns/63-const-generics-in-generic-components.problem.tsx b/src/08-advanced-patterns/64-const-generics-in-generic-components.problem.tsx similarity index 100% rename from src/08-advanced-patterns/63-const-generics-in-generic-components.problem.tsx rename to src/08-advanced-patterns/64-const-generics-in-generic-components.problem.tsx diff --git a/src/08-advanced-patterns/64-render-props.problem.tsx b/src/08-advanced-patterns/65-render-props.problem.tsx similarity index 100% rename from src/08-advanced-patterns/64-render-props.problem.tsx rename to src/08-advanced-patterns/65-render-props.problem.tsx diff --git a/src/08-advanced-patterns/64-render-props.solution.tsx b/src/08-advanced-patterns/65-render-props.solution.tsx similarity index 100% rename from src/08-advanced-patterns/64-render-props.solution.tsx rename to src/08-advanced-patterns/65-render-props.solution.tsx diff --git a/src/08-advanced-patterns/65-forward-ref-with-generics.explainer.1.tsx b/src/08-advanced-patterns/66-forward-ref-with-generics.explainer.1.tsx similarity index 100% rename from src/08-advanced-patterns/65-forward-ref-with-generics.explainer.1.tsx rename to src/08-advanced-patterns/66-forward-ref-with-generics.explainer.1.tsx diff --git a/src/08-advanced-patterns/65-forward-ref-with-generics.explainer.2.tsx b/src/08-advanced-patterns/66-forward-ref-with-generics.explainer.2.tsx similarity index 100% rename from src/08-advanced-patterns/65-forward-ref-with-generics.explainer.2.tsx rename to src/08-advanced-patterns/66-forward-ref-with-generics.explainer.2.tsx diff --git a/src/08-advanced-patterns/65-forward-ref-with-generics.explainer.3.ts b/src/08-advanced-patterns/66-forward-ref-with-generics.explainer.3.ts similarity index 100% rename from src/08-advanced-patterns/65-forward-ref-with-generics.explainer.3.ts rename to src/08-advanced-patterns/66-forward-ref-with-generics.explainer.3.ts diff --git a/src/08-advanced-patterns/66-forward-ref-as-local-function.problem.tsx b/src/08-advanced-patterns/67-forward-ref-as-local-function.problem.tsx similarity index 100% rename from src/08-advanced-patterns/66-forward-ref-as-local-function.problem.tsx rename to src/08-advanced-patterns/67-forward-ref-as-local-function.problem.tsx diff --git a/src/08-advanced-patterns/66-forward-ref-as-local-function.solution.tsx b/src/08-advanced-patterns/67-forward-ref-as-local-function.solution.tsx similarity index 100% rename from src/08-advanced-patterns/66-forward-ref-as-local-function.solution.tsx rename to src/08-advanced-patterns/67-forward-ref-as-local-function.solution.tsx diff --git a/src/08-advanced-patterns/67-hoc.problem.tsx b/src/08-advanced-patterns/68-hoc.problem.tsx similarity index 100% rename from src/08-advanced-patterns/67-hoc.problem.tsx rename to src/08-advanced-patterns/68-hoc.problem.tsx diff --git a/src/08-advanced-patterns/67-hoc.solution.tsx b/src/08-advanced-patterns/68-hoc.solution.tsx similarity index 100% rename from src/08-advanced-patterns/67-hoc.solution.tsx rename to src/08-advanced-patterns/68-hoc.solution.tsx diff --git a/src/08-advanced-patterns/68-record-of-components-with-same-props.problem.tsx b/src/08-advanced-patterns/69-record-of-components-with-same-props.problem.tsx similarity index 100% rename from src/08-advanced-patterns/68-record-of-components-with-same-props.problem.tsx rename to src/08-advanced-patterns/69-record-of-components-with-same-props.problem.tsx diff --git a/src/08-advanced-patterns/68-record-of-components-with-same-props.solution.1.tsx b/src/08-advanced-patterns/69-record-of-components-with-same-props.solution.1.tsx similarity index 100% rename from src/08-advanced-patterns/68-record-of-components-with-same-props.solution.1.tsx rename to src/08-advanced-patterns/69-record-of-components-with-same-props.solution.1.tsx diff --git a/src/08-advanced-patterns/68-record-of-components-with-same-props.solution.2.tsx b/src/08-advanced-patterns/69-record-of-components-with-same-props.solution.2.tsx similarity index 100% rename from src/08-advanced-patterns/68-record-of-components-with-same-props.solution.2.tsx rename to src/08-advanced-patterns/69-record-of-components-with-same-props.solution.2.tsx diff --git a/src/08-advanced-patterns/69-as-prop.problem.tsx b/src/08-advanced-patterns/70-as-prop.problem.tsx similarity index 100% rename from src/08-advanced-patterns/69-as-prop.problem.tsx rename to src/08-advanced-patterns/70-as-prop.problem.tsx diff --git a/src/08-advanced-patterns/69-as-prop.solution.1.tsx b/src/08-advanced-patterns/70-as-prop.solution.1.tsx similarity index 100% rename from src/08-advanced-patterns/69-as-prop.solution.1.tsx rename to src/08-advanced-patterns/70-as-prop.solution.1.tsx diff --git a/src/08-advanced-patterns/69-as-prop.solution.2.tsx b/src/08-advanced-patterns/70-as-prop.solution.2.tsx similarity index 100% rename from src/08-advanced-patterns/69-as-prop.solution.2.tsx rename to src/08-advanced-patterns/70-as-prop.solution.2.tsx diff --git a/src/08-advanced-patterns/70-as-prop-with-custom-components.problem.tsx b/src/08-advanced-patterns/71-as-prop-with-custom-components.problem.tsx similarity index 100% rename from src/08-advanced-patterns/70-as-prop-with-custom-components.problem.tsx rename to src/08-advanced-patterns/71-as-prop-with-custom-components.problem.tsx diff --git a/src/08-advanced-patterns/70-as-prop-with-custom-components.solution.tsx b/src/08-advanced-patterns/71-as-prop-with-custom-components.solution.tsx similarity index 100% rename from src/08-advanced-patterns/70-as-prop-with-custom-components.solution.tsx rename to src/08-advanced-patterns/71-as-prop-with-custom-components.solution.tsx diff --git a/src/08-advanced-patterns/71-as-prop-with-default.problem.tsx b/src/08-advanced-patterns/72-as-prop-with-default.problem.tsx similarity index 100% rename from src/08-advanced-patterns/71-as-prop-with-default.problem.tsx rename to src/08-advanced-patterns/72-as-prop-with-default.problem.tsx diff --git a/src/08-advanced-patterns/71-as-prop-with-default.solution.tsx b/src/08-advanced-patterns/72-as-prop-with-default.solution.tsx similarity index 100% rename from src/08-advanced-patterns/71-as-prop-with-default.solution.tsx rename to src/08-advanced-patterns/72-as-prop-with-default.solution.tsx diff --git a/src/09-external-libraries/72-react-hook-form.explainer.tsx b/src/09-external-libraries/73-react-hook-form.explainer.tsx similarity index 100% rename from src/09-external-libraries/72-react-hook-form.explainer.tsx rename to src/09-external-libraries/73-react-hook-form.explainer.tsx diff --git a/src/09-external-libraries/73-react-hook-form-wrapper.problem.tsx b/src/09-external-libraries/74-react-hook-form-wrapper.problem.tsx similarity index 100% rename from src/09-external-libraries/73-react-hook-form-wrapper.problem.tsx rename to src/09-external-libraries/74-react-hook-form-wrapper.problem.tsx diff --git a/src/09-external-libraries/73-react-hook-form-wrapper.solution.tsx b/src/09-external-libraries/74-react-hook-form-wrapper.solution.tsx similarity index 100% rename from src/09-external-libraries/73-react-hook-form-wrapper.solution.tsx rename to src/09-external-libraries/74-react-hook-form-wrapper.solution.tsx diff --git a/src/09-external-libraries/74-react-select.problem.tsx b/src/09-external-libraries/75-react-select.problem.tsx similarity index 100% rename from src/09-external-libraries/74-react-select.problem.tsx rename to src/09-external-libraries/75-react-select.problem.tsx diff --git a/src/09-external-libraries/74-react-select.solution.tsx b/src/09-external-libraries/75-react-select.solution.tsx similarity index 100% rename from src/09-external-libraries/74-react-select.solution.tsx rename to src/09-external-libraries/75-react-select.solution.tsx diff --git a/src/09-external-libraries/75-react-query.explainer.ts b/src/09-external-libraries/76-react-query.explainer.ts similarity index 100% rename from src/09-external-libraries/75-react-query.explainer.ts rename to src/09-external-libraries/76-react-query.explainer.ts diff --git a/src/09-external-libraries/76-react-query-wrapper.problem.ts b/src/09-external-libraries/77-react-query-wrapper.problem.ts similarity index 100% rename from src/09-external-libraries/76-react-query-wrapper.problem.ts rename to src/09-external-libraries/77-react-query-wrapper.problem.ts diff --git a/src/09-external-libraries/76-react-query-wrapper.solution.ts b/src/09-external-libraries/77-react-query-wrapper.solution.ts similarity index 100% rename from src/09-external-libraries/76-react-query-wrapper.solution.ts rename to src/09-external-libraries/77-react-query-wrapper.solution.ts From 0c6407fa3bdd6947fa828aad4748823c5a735a86 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 17 Jul 2023 10:49:39 +0100 Subject: [PATCH 012/105] Updated snapshots --- scripts/tests/__snapshots__/all.test.ts.snap | 592 +++++++++++-------- 1 file changed, 341 insertions(+), 251 deletions(-) diff --git a/scripts/tests/__snapshots__/all.test.ts.snap b/scripts/tests/__snapshots__/all.test.ts.snap index b5a7a33..35cfd0f 100644 --- a/scripts/tests/__snapshots__/all.test.ts.snap +++ b/scripts/tests/__snapshots__/all.test.ts.snap @@ -101,109 +101,127 @@ src/04-advanced-props/33-prop-groups-with-variants.problem.tsx(48,11): error TS2 Type '{ children: string; className: string; type: string; illegalProperty: string; }' is not assignable to type 'ButtonHTMLAttributes'. Types of property 'type' are incompatible. Type 'string' is not assignable to type '\\"button\\" | \\"submit\\" | \\"reset\\" | undefined'. -src/05-generics/34-generic-props.problem.tsx(41,30): error TS2344: Type 'false' does not satisfy the constraint 'true'. -src/05-generics/34-generic-props.problem.tsx(45,17): error TS2578: Unused '@ts-expect-error' directive. -src/05-generics/35-generic-hooks.problem.ts(23,10): error TS2344: Type 'false' does not satisfy the constraint 'true'. -src/05-generics/35-generic-hooks.problem.ts(25,5): error TS2344: Type 'false' does not satisfy the constraint 'true'. -src/05-generics/35-generic-hooks.problem.ts(35,10): error TS2344: Type 'false' does not satisfy the constraint 'true'. -src/05-generics/35-generic-hooks.problem.ts(36,10): error TS2344: Type 'false' does not satisfy the constraint 'true'. -src/05-generics/35.5-generic-class-components.problem.tsx(37,30): error TS2344: Type 'false' does not satisfy the constraint 'true'. -src/05-generics/35.5-generic-class-components.problem.tsx(41,17): error TS2578: Unused '@ts-expect-error' directive. -src/05-generics/36-generic-localstorage-hook.problem.ts(28,30): error TS2558: Expected 0 type arguments, but got 1. -src/05-generics/36-generic-localstorage-hook.problem.ts(35,24): error TS2344: Type 'false' does not satisfy the constraint 'true'. -src/05-generics/36-generic-localstorage-hook.problem.ts(41,5): error TS2578: Unused '@ts-expect-error' directive. -src/05-generics/37-generic-inference-through-multiple-helpers.problem.tsx(44,26): error TS2344: Type 'false' does not satisfy the constraint 'true'. -src/05-generics/37.2-inference-flow-with-constraints.problem.ts(42,1): error TS2578: Unused '@ts-expect-error' directive. -src/05-generics/37.2-inference-flow-with-constraints.problem.ts(52,5): error TS2578: Unused '@ts-expect-error' directive. -src/05-generics/37.2-inference-flow-with-constraints.problem.ts(60,5): error TS2344: Type 'false' does not satisfy the constraint 'true'. -src/05-generics/38-button-group.problem.tsx(46,26): error TS2344: Type 'false' does not satisfy the constraint 'true'. -src/05-generics/39-lazy-load-component.problem.tsx(18,44): error TS2345: Argument of type 'unknown' is not assignable to parameter of type '() => Promise<{ default: ComponentType; }>'. -src/05-generics/39-lazy-load-component.problem.tsx(28,62): error TS2322: Type '{ loader: () => Promise; id: string; }' is not assignable to type 'IntrinsicAttributes & Props'. - Property 'id' does not exist on type 'IntrinsicAttributes & Props'. -src/05-generics/39-lazy-load-component.problem.tsx(36,4): error TS2578: Unused '@ts-expect-error' directive. -src/06-advanced-hooks/41-tuple-return-type.problem.ts(23,10): error TS2344: Type 'false' does not satisfy the constraint 'true'. -src/06-advanced-hooks/41-tuple-return-type.problem.ts(24,10): error TS2344: Type 'false' does not satisfy the constraint 'true'. -src/06-advanced-hooks/42-unions-in-usestate.problem.tsx(45,3): error TS2578: Unused '@ts-expect-error' directive. -src/06-advanced-hooks/42-unions-in-usestate.problem.tsx(62,22): error TS2344: Type 'false' does not satisfy the constraint 'true'. -src/06-advanced-hooks/43-discriminated-unions-in-usestate.problem.tsx(44,3): error TS2578: Unused '@ts-expect-error' directive. -src/06-advanced-hooks/43-discriminated-unions-in-usestate.problem.tsx(47,3): error TS2578: Unused '@ts-expect-error' directive. -src/06-advanced-hooks/43-discriminated-unions-in-usestate.problem.tsx(50,3): error TS2578: Unused '@ts-expect-error' directive. -src/06-advanced-hooks/44-discriminated-tuples-from-custom-hooks.problem.tsx(46,25): error TS18048: 'value' is possibly 'undefined'. -src/06-advanced-hooks/44-discriminated-tuples-from-custom-hooks.problem.tsx(46,31): error TS2339: Property 'message' does not exist on type 'Error | { title: string; }'. +src/05-generics/36-type-helpers-with-constraints.problem.tsx(14,3): error TS2578: Unused '@ts-expect-error' directive. +src/05-generics/36-type-helpers-with-constraints.problem.tsx(16,3): error TS2578: Unused '@ts-expect-error' directive. +src/05-generics/36-type-helpers-with-constraints.problem.tsx(18,3): error TS2578: Unused '@ts-expect-error' directive. +src/05-generics/37-generic-localstorage-hook.problem.ts(28,30): error TS2558: Expected 0 type arguments, but got 1. +src/05-generics/37-generic-localstorage-hook.problem.ts(35,24): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/05-generics/37-generic-localstorage-hook.problem.ts(41,5): error TS2578: Unused '@ts-expect-error' directive. +src/05-generics/38-generic-hooks.problem.ts(23,10): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/05-generics/38-generic-hooks.problem.ts(25,5): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/05-generics/38-generic-hooks.problem.ts(35,10): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/05-generics/38-generic-hooks.problem.ts(36,10): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/05-generics/39-generic-props.problem.tsx(41,30): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/05-generics/39-generic-props.problem.tsx(45,17): error TS2578: Unused '@ts-expect-error' directive. +src/05-generics/40-generic-class-components.problem.tsx(37,30): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/05-generics/40-generic-class-components.problem.tsx(41,17): error TS2578: Unused '@ts-expect-error' directive. +src/05-generics/41-passing-types-to-components.problem.tsx(29,5): error TS2578: Unused '@ts-expect-error' directive. +src/05-generics/41-passing-types-to-components.problem.tsx(32,26): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/05-generics/41-passing-types-to-components.problem.tsx(33,23): error TS2339: Property 'name' does not exist on type 'number'. +src/05-generics/41-passing-types-to-components.problem.tsx(44,9): error TS2578: Unused '@ts-expect-error' directive. +src/05-generics/41-passing-types-to-components.problem.tsx(51,26): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/05-generics/42-generic-inference-through-multiple-helpers.problem.tsx(44,26): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/05-generics/42-passing-types-to-components.problem.tsx(35,26): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/05-generics/42-passing-types-to-components.problem.tsx(36,23): error TS2339: Property 'name' does not exist on type 'number'. +src/05-generics/42-passing-types-to-components.problem.tsx(47,9): error TS2578: Unused '@ts-expect-error' directive. +src/05-generics/42-passing-types-to-components.problem.tsx(54,26): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/05-generics/43-inference-flow-with-constraints.problem.ts(42,1): error TS2578: Unused '@ts-expect-error' directive. +src/05-generics/43-inference-flow-with-constraints.problem.ts(52,5): error TS2578: Unused '@ts-expect-error' directive. +src/05-generics/43-inference-flow-with-constraints.problem.ts(60,5): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/06-advanced-hooks/45-tuple-return-type.problem.ts(23,10): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/06-advanced-hooks/45-tuple-return-type.problem.ts(24,10): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/06-advanced-hooks/46-required-context.problem.tsx(33,55): error TS2558: Expected 0 type arguments, but got 1. +src/06-advanced-hooks/46-required-context.problem.tsx(37,57): error TS2558: Expected 0 type arguments, but got 1. +src/06-advanced-hooks/46-required-context.problem.tsx(42,16): error TS2554: Expected 1 arguments, but got 0. +src/06-advanced-hooks/46-required-context.problem.tsx(45,5): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/06-advanced-hooks/46-required-context.problem.tsx(53,17): error TS2554: Expected 1 arguments, but got 0. +src/06-advanced-hooks/46-required-context.problem.tsx(56,5): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/06-advanced-hooks/46-required-context.problem.tsx(70,21): error TS2322: Type '{ name: string; }' is not assignable to type 'null'. +src/06-advanced-hooks/46-required-context.problem.tsx(72,11): error TS2322: Type '{ primaryColor: string; }' is not assignable to type 'null'. +src/06-advanced-hooks/47-unions-in-usestate.problem.tsx(45,3): error TS2578: Unused '@ts-expect-error' directive. +src/06-advanced-hooks/47-unions-in-usestate.problem.tsx(62,22): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/06-advanced-hooks/48-discriminated-unions-in-usestate.problem.tsx(28,37): error TS2345: Argument of type '{ status: string; error: any; }' is not assignable to parameter of type 'SetStateAction<{ status: string; }>'. + Object literal may only specify known properties, and 'error' does not exist in type 'SetStateAction<{ status: string; }>'. +src/06-advanced-hooks/48-discriminated-unions-in-usestate.problem.tsx(36,3): error TS2578: Unused '@ts-expect-error' directive. +src/06-advanced-hooks/48-discriminated-unions-in-usestate.problem.tsx(46,25): error TS2339: Property 'error' does not exist on type '{ status: string; }'. +src/06-advanced-hooks/49-discriminated-tuples-from-custom-hooks.problem.tsx(46,25): error TS18048: 'value' is possibly 'undefined'. +src/06-advanced-hooks/49-discriminated-tuples-from-custom-hooks.problem.tsx(46,31): error TS2339: Property 'message' does not exist on type 'Error | { title: string; }'. Property 'message' does not exist on type '{ title: string; }'. -src/06-advanced-hooks/44-discriminated-tuples-from-custom-hooks.problem.tsx(49,16): error TS18048: 'value' is possibly 'undefined'. -src/06-advanced-hooks/44-discriminated-tuples-from-custom-hooks.problem.tsx(49,22): error TS2339: Property 'title' does not exist on type 'Error | { title: string; }'. +src/06-advanced-hooks/49-discriminated-tuples-from-custom-hooks.problem.tsx(49,16): error TS18048: 'value' is possibly 'undefined'. +src/06-advanced-hooks/49-discriminated-tuples-from-custom-hooks.problem.tsx(49,22): error TS2339: Property 'title' does not exist on type 'Error | { title: string; }'. Property 'title' does not exist on type 'Error'. -src/06-advanced-hooks/45-use-state-overloads.problem.ts(36,10): error TS2344: Type 'false' does not satisfy the constraint 'true'. -src/06-advanced-hooks/46-function-overloads-in-hooks.problem.ts(37,22): error TS2554: Expected 1 arguments, but got 0. -src/06-advanced-hooks/46-function-overloads-in-hooks.problem.ts(40,10): error TS2344: Type 'false' does not satisfy the constraint 'true'. -src/06-advanced-hooks/46-function-overloads-in-hooks.problem.ts(42,5): error TS2344: Type 'false' does not satisfy the constraint 'true'. -src/07-types-deep-dive/48-understanding-jsx-element.explainer.tsx(52,3): error TS2322: Type 'string' is not assignable to type 'ReactElement>'. -src/07-types-deep-dive/49-strongly-typing-children.explainer.tsx(32,3): error TS2322: Type 'Element' is not assignable to type 'OptionType'. +src/06-advanced-hooks/50-use-state-overloads.problem.ts(36,10): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/06-advanced-hooks/51-function-overloads-in-hooks.problem.ts(37,22): error TS2554: Expected 1 arguments, but got 0. +src/06-advanced-hooks/51-function-overloads-in-hooks.problem.ts(40,10): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/06-advanced-hooks/51-function-overloads-in-hooks.problem.ts(42,5): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/06-advanced-hooks/52-currying-hooks.problem.ts(38,22): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/07-types-deep-dive/54-understanding-jsx-element.explainer.tsx(52,3): error TS2322: Type 'string' is not assignable to type 'ReactElement>'. +src/07-types-deep-dive/55-strongly-typing-children.explainer.tsx(32,3): error TS2322: Type 'Element' is not assignable to type 'OptionType'. Type 'ReactElement' is not assignable to type '{ __brand: \\"OPTION_TYPE\\"; } & ReactPortal'. Property '__brand' is missing in type 'ReactElement' but required in type '{ __brand: \\"OPTION_TYPE\\"; }'. -src/07-types-deep-dive/50-understanding-jsx-intrinsic-elements.explainer.tsx(30,1): error TS2339: Property 'myNewElement' does not exist on type 'JSX.IntrinsicElements'. -src/07-types-deep-dive/51-appending-to-global-namespace.problem.ts(15,20): error TS2344: Type 'false' does not satisfy the constraint 'true'. -src/07-types-deep-dive/51-appending-to-global-namespace.problem.ts(15,32): error TS2694: Namespace 'React' has no exported member 'MyInterface'. -src/07-types-deep-dive/52-declaration-merging-in-global-namespace.problem.ts(25,3): error TS2344: Type 'false' does not satisfy the constraint 'true'. -src/07-types-deep-dive/53-add-new-global-element.problem.tsx(14,3): error TS2339: Property 'something' does not exist on type 'JSX.IntrinsicElements'. -src/07-types-deep-dive/53-add-new-global-element.problem.tsx(14,23): error TS2339: Property 'something' does not exist on type 'JSX.IntrinsicElements'. -src/07-types-deep-dive/55-add-attribute-to-all-elements.problem.tsx(10,8): error TS2322: Type '{ testId: string; }' is not assignable to type 'DetailedHTMLProps, HTMLDivElement>'. +src/07-types-deep-dive/56-understanding-jsx-intrinsic-elements.explainer.tsx(30,1): error TS2339: Property 'myNewElement' does not exist on type 'JSX.IntrinsicElements'. +src/07-types-deep-dive/58-appending-to-global-namespace.problem.ts(15,20): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/07-types-deep-dive/58-appending-to-global-namespace.problem.ts(15,32): error TS2694: Namespace 'React' has no exported member 'MyInterface'. +src/07-types-deep-dive/59-declaration-merging-in-global-namespace.problem.ts(25,3): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/07-types-deep-dive/60-add-new-global-element.problem.tsx(14,3): error TS2339: Property 'something' does not exist on type 'JSX.IntrinsicElements'. +src/07-types-deep-dive/60-add-new-global-element.problem.tsx(14,23): error TS2339: Property 'something' does not exist on type 'JSX.IntrinsicElements'. +src/07-types-deep-dive/62-add-attribute-to-all-elements.problem.tsx(10,8): error TS2322: Type '{ testId: string; }' is not assignable to type 'DetailedHTMLProps, HTMLDivElement>'. Property 'testId' does not exist on type 'DetailedHTMLProps, HTMLDivElement>'. -src/07-types-deep-dive/55-add-attribute-to-all-elements.problem.tsx(11,10): error TS2322: Type '{ testId: string; }' is not assignable to type 'DetailedHTMLProps, HTMLAudioElement>'. +src/07-types-deep-dive/62-add-attribute-to-all-elements.problem.tsx(11,10): error TS2322: Type '{ testId: string; }' is not assignable to type 'DetailedHTMLProps, HTMLAudioElement>'. Property 'testId' does not exist on type 'DetailedHTMLProps, HTMLAudioElement>'. -src/07-types-deep-dive/55-add-attribute-to-all-elements.problem.tsx(12,10): error TS2322: Type '{ testId: string; }' is not assignable to type 'DetailedHTMLProps, HTMLVideoElement>'. +src/07-types-deep-dive/62-add-attribute-to-all-elements.problem.tsx(12,10): error TS2322: Type '{ testId: string; }' is not assignable to type 'DetailedHTMLProps, HTMLVideoElement>'. Property 'testId' does not exist on type 'DetailedHTMLProps, HTMLVideoElement>'. -src/07-types-deep-dive/55-add-attribute-to-all-elements.problem.tsx(13,6): error TS2322: Type '{ testId: string; }' is not assignable to type 'DetailedHTMLProps, HTMLAnchorElement>'. +src/07-types-deep-dive/62-add-attribute-to-all-elements.problem.tsx(13,6): error TS2322: Type '{ testId: string; }' is not assignable to type 'DetailedHTMLProps, HTMLAnchorElement>'. Property 'testId' does not exist on type 'DetailedHTMLProps, HTMLAnchorElement>'. -src/07-types-deep-dive/55-add-attribute-to-all-elements.problem.tsx(14,9): error TS2322: Type '{ testId: string; }' is not assignable to type 'DetailedHTMLProps, HTMLElement>'. +src/07-types-deep-dive/62-add-attribute-to-all-elements.problem.tsx(14,9): error TS2322: Type '{ testId: string; }' is not assignable to type 'DetailedHTMLProps, HTMLElement>'. Property 'testId' does not exist on type 'DetailedHTMLProps, HTMLElement>'. -src/07-types-deep-dive/55-add-attribute-to-all-elements.problem.tsx(15,12): error TS2322: Type '{ testId: string; }' is not assignable to type 'DetailedHTMLProps, HTMLElement>'. +src/07-types-deep-dive/62-add-attribute-to-all-elements.problem.tsx(15,12): error TS2322: Type '{ testId: string; }' is not assignable to type 'DetailedHTMLProps, HTMLElement>'. Property 'testId' does not exist on type 'DetailedHTMLProps, HTMLElement>'. -src/08-advanced-patterns/56-required-context.problem.tsx(33,55): error TS2558: Expected 0 type arguments, but got 1. -src/08-advanced-patterns/56-required-context.problem.tsx(37,57): error TS2558: Expected 0 type arguments, but got 1. -src/08-advanced-patterns/56-required-context.problem.tsx(42,16): error TS2554: Expected 1 arguments, but got 0. -src/08-advanced-patterns/56-required-context.problem.tsx(45,5): error TS2344: Type 'false' does not satisfy the constraint 'true'. -src/08-advanced-patterns/56-required-context.problem.tsx(53,17): error TS2554: Expected 1 arguments, but got 0. -src/08-advanced-patterns/56-required-context.problem.tsx(56,5): error TS2344: Type 'false' does not satisfy the constraint 'true'. -src/08-advanced-patterns/56-required-context.problem.tsx(70,21): error TS2322: Type '{ name: string; }' is not assignable to type 'null'. -src/08-advanced-patterns/56-required-context.problem.tsx(72,11): error TS2322: Type '{ primaryColor: string; }' is not assignable to type 'null'. -src/08-advanced-patterns/57-render-props.problem.tsx(43,9): error TS7006: Parameter 'props' implicitly has an 'any' type. -src/08-advanced-patterns/57-render-props.problem.tsx(44,28): error TS2344: Type 'false' does not satisfy the constraint 'true'. -src/08-advanced-patterns/58-forward-ref-with-generics.explainer.1.tsx(45,28): error TS2344: Type 'false' does not satisfy the constraint 'true'. -src/08-advanced-patterns/58-forward-ref-with-generics.explainer.2.tsx(26,28): error TS2344: Type 'false' does not satisfy the constraint 'true'. -src/08-advanced-patterns/58-forward-ref-with-generics.explainer.3.ts(52,21): error TS2344: Type 'false' does not satisfy the constraint 'true'. -src/08-advanced-patterns/59-hoc.problem.tsx(43,5): error TS2578: Unused '@ts-expect-error' directive. -src/08-advanced-patterns/60-record-of-components-with-same-props.problem.tsx(16,10): error TS7006: Parameter 'props' implicitly has an 'any' type. -src/08-advanced-patterns/60-record-of-components-with-same-props.problem.tsx(19,12): error TS7006: Parameter 'props' implicitly has an 'any' type. -src/08-advanced-patterns/60-record-of-components-with-same-props.problem.tsx(22,14): error TS7006: Parameter 'props' implicitly has an 'any' type. -src/08-advanced-patterns/60-record-of-components-with-same-props.problem.tsx(28,21): error TS7053: Element implicitly has an 'any' type because expression of type 'any' can't be used to index type '{ text: (props: any) => Element; number: (props: any) => Element; password: (props: any) => Element; }'. -src/08-advanced-patterns/60-record-of-components-with-same-props.problem.tsx(28,32): error TS18046: 'props' is of type 'unknown'. -src/08-advanced-patterns/60-record-of-components-with-same-props.problem.tsx(29,25): error TS2698: Spread types may only be created from object types. -src/08-advanced-patterns/60-record-of-components-with-same-props.problem.tsx(34,5): error TS2322: Type '{ type: string; onChange: (e: any) => void; }' is not assignable to type 'IntrinsicAttributes'. +src/08-advanced-patterns/63-lazy-load-component.problem.tsx(18,44): error TS2345: Argument of type 'unknown' is not assignable to parameter of type '() => Promise<{ default: ComponentType; }>'. +src/08-advanced-patterns/63-lazy-load-component.problem.tsx(28,62): error TS2322: Type '{ loader: () => Promise; id: string; }' is not assignable to type 'IntrinsicAttributes & Props'. + Property 'id' does not exist on type 'IntrinsicAttributes & Props'. +src/08-advanced-patterns/63-lazy-load-component.problem.tsx(36,4): error TS2578: Unused '@ts-expect-error' directive. +src/08-advanced-patterns/65-render-props.problem.tsx(43,9): error TS7006: Parameter 'props' implicitly has an 'any' type. +src/08-advanced-patterns/65-render-props.problem.tsx(44,28): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/08-advanced-patterns/66-forward-ref-with-generics.explainer.1.tsx(45,28): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/08-advanced-patterns/66-forward-ref-with-generics.explainer.2.tsx(26,28): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/08-advanced-patterns/66-forward-ref-with-generics.explainer.3.ts(52,21): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/08-advanced-patterns/67-forward-ref-as-local-function.problem.tsx(30,19): error TS7006: Parameter 'row' implicitly has an 'any' type. +src/08-advanced-patterns/67-forward-ref-as-local-function.problem.tsx(31,28): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/08-advanced-patterns/68-hoc.problem.tsx(43,5): error TS2578: Unused '@ts-expect-error' directive. +src/08-advanced-patterns/69-record-of-components-with-same-props.problem.tsx(16,10): error TS7006: Parameter 'props' implicitly has an 'any' type. +src/08-advanced-patterns/69-record-of-components-with-same-props.problem.tsx(19,12): error TS7006: Parameter 'props' implicitly has an 'any' type. +src/08-advanced-patterns/69-record-of-components-with-same-props.problem.tsx(22,14): error TS7006: Parameter 'props' implicitly has an 'any' type. +src/08-advanced-patterns/69-record-of-components-with-same-props.problem.tsx(28,21): error TS7053: Element implicitly has an 'any' type because expression of type 'any' can't be used to index type '{ text: (props: any) => Element; number: (props: any) => Element; password: (props: any) => Element; }'. +src/08-advanced-patterns/69-record-of-components-with-same-props.problem.tsx(28,32): error TS18046: 'props' is of type 'unknown'. +src/08-advanced-patterns/69-record-of-components-with-same-props.problem.tsx(29,25): error TS2698: Spread types may only be created from object types. +src/08-advanced-patterns/69-record-of-components-with-same-props.problem.tsx(34,5): error TS2322: Type '{ type: string; onChange: (e: any) => void; }' is not assignable to type 'IntrinsicAttributes'. Property 'type' does not exist on type 'IntrinsicAttributes'. -src/08-advanced-patterns/60-record-of-components-with-same-props.problem.tsx(35,16): error TS7006: Parameter 'e' implicitly has an 'any' type. -src/08-advanced-patterns/60-record-of-components-with-same-props.problem.tsx(37,26): error TS2344: Type 'false' does not satisfy the constraint 'true'. -src/08-advanced-patterns/60-record-of-components-with-same-props.problem.tsx(40,10): error TS2322: Type '{ type: string; }' is not assignable to type 'IntrinsicAttributes'. +src/08-advanced-patterns/69-record-of-components-with-same-props.problem.tsx(35,16): error TS7006: Parameter 'e' implicitly has an 'any' type. +src/08-advanced-patterns/69-record-of-components-with-same-props.problem.tsx(37,26): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/08-advanced-patterns/69-record-of-components-with-same-props.problem.tsx(40,10): error TS2322: Type '{ type: string; }' is not assignable to type 'IntrinsicAttributes'. Property 'type' does not exist on type 'IntrinsicAttributes'. -src/08-advanced-patterns/60-record-of-components-with-same-props.problem.tsx(41,10): error TS2322: Type '{ type: string; }' is not assignable to type 'IntrinsicAttributes'. +src/08-advanced-patterns/69-record-of-components-with-same-props.problem.tsx(41,10): error TS2322: Type '{ type: string; }' is not assignable to type 'IntrinsicAttributes'. Property 'type' does not exist on type 'IntrinsicAttributes'. -src/08-advanced-patterns/61-as-prop.problem.tsx(37,5): error TS2578: Unused '@ts-expect-error' directive. -src/08-advanced-patterns/62-as-prop-with-custom-components.problem.tsx(14,11): error TS2604: JSX element type 'Comp' does not have any construct or call signatures. -src/08-advanced-patterns/62-as-prop-with-custom-components.problem.tsx(14,11): error TS2786: 'Comp' cannot be used as a JSX component. +src/08-advanced-patterns/70-as-prop.problem.tsx(37,5): error TS2578: Unused '@ts-expect-error' directive. +src/08-advanced-patterns/71-as-prop-with-custom-components.problem.tsx(14,11): error TS2604: JSX element type 'Comp' does not have any construct or call signatures. +src/08-advanced-patterns/71-as-prop-with-custom-components.problem.tsx(14,11): error TS2786: 'Comp' cannot be used as a JSX component. Its type 'unknown' is not a valid JSX element type. -src/08-advanced-patterns/62-as-prop-with-custom-components.problem.tsx(21,20): error TS2322: Type '{ as: (props: { href: string; children?: ReactNode; }) => Element; href: string; }' is not assignable to type 'IntrinsicAttributes & { as: unknown; }'. +src/08-advanced-patterns/71-as-prop-with-custom-components.problem.tsx(21,20): error TS2322: Type '{ as: (props: { href: string; children?: ReactNode; }) => Element; href: string; }' is not assignable to type 'IntrinsicAttributes & { as: unknown; }'. Property 'href' does not exist on type 'IntrinsicAttributes & { as: unknown; }'. -src/09-external-libraries/64-react-hook-form-wrapper.problem.tsx(29,3): error TS2578: Unused '@ts-expect-error' directive. -src/09-external-libraries/64-react-hook-form-wrapper.problem.tsx(42,5): error TS2344: Type 'boolean' does not satisfy the constraint 'true'. -src/09-external-libraries/65-react-select.problem.tsx(10,24): error TS7006: Parameter 'props' implicitly has an 'any' type. -src/09-external-libraries/65-react-select.problem.tsx(33,16): error TS7006: Parameter 'option' implicitly has an 'any' type. -src/09-external-libraries/65-react-select.problem.tsx(36,26): error TS2344: Type 'false' does not satisfy the constraint 'true'. -src/09-external-libraries/65-react-select.problem.tsx(43,16): error TS7006: Parameter 'option' implicitly has an 'any' type. -src/09-external-libraries/65-react-select.problem.tsx(45,26): error TS2344: Type 'false' does not satisfy the constraint 'true'. -src/09-external-libraries/67-react-query-wrapper.problem.ts(30,12): error TS2344: Type 'false' does not satisfy the constraint 'true'. -src/09-external-libraries/67-react-query-wrapper.problem.ts(44,10): error TS2344: Type 'false' does not satisfy the constraint 'true'. -src/09-external-libraries/67-react-query-wrapper.problem.ts(50,22): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/08-advanced-patterns/72-as-prop-with-default.problem.tsx(10,11): error TS2322: Type 'Omit<{ as: T; } & ComponentPropsWithoutRef, \\"as\\">' is not assignable to type 'IntrinsicAttributes & LibraryManagedAttributes'. + Type 'Omit<{ as: T; } & ComponentPropsWithoutRef, \\"as\\">' is not assignable to type 'LibraryManagedAttributes'. +src/08-advanced-patterns/72-as-prop-with-default.problem.tsx(14,2): error TS2741: Property 'as' is missing in type '{ href: string; }' but required in type '{ as: ElementType; }'. +src/09-external-libraries/74-react-hook-form-wrapper.problem.tsx(29,3): error TS2578: Unused '@ts-expect-error' directive. +src/09-external-libraries/74-react-hook-form-wrapper.problem.tsx(42,5): error TS2344: Type 'boolean' does not satisfy the constraint 'true'. +src/09-external-libraries/75-react-select.problem.tsx(10,24): error TS7006: Parameter 'props' implicitly has an 'any' type. +src/09-external-libraries/75-react-select.problem.tsx(33,16): error TS7006: Parameter 'option' implicitly has an 'any' type. +src/09-external-libraries/75-react-select.problem.tsx(36,26): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/09-external-libraries/75-react-select.problem.tsx(43,16): error TS7006: Parameter 'option' implicitly has an 'any' type. +src/09-external-libraries/75-react-select.problem.tsx(45,26): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/09-external-libraries/77-react-query-wrapper.problem.ts(30,12): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/09-external-libraries/77-react-query-wrapper.problem.ts(44,10): error TS2344: Type 'false' does not satisfy the constraint 'true'. +src/09-external-libraries/77-react-query-wrapper.problem.ts(50,22): error TS2344: Type 'false' does not satisfy the constraint 'true'. ," `; @@ -670,74 +688,44 @@ exports[`vitest > Should have the correct Vitest errors 1`] = ` }, { "assertionResults": [], - "message": "No test found in suite src/05-generics/33.5-type-helpers.problem.tsx", - "name": "/src/05-generics/33.5-type-helpers.problem.tsx", - "status": "passed", - }, - { - "assertionResults": [], - "message": "No test found in suite src/05-generics/33.6-type-helpers-with-constraints.problem.tsx", - "name": "/src/05-generics/33.6-type-helpers-with-constraints.problem.tsx", - "status": "passed", - }, - { - "assertionResults": [], - "message": "No test found in suite src/05-generics/34-generic-props.problem.tsx", - "name": "/src/05-generics/34-generic-props.problem.tsx", + "message": "No test found in suite src/05-generics/34-type-helpers.problem.tsx", + "name": "/src/05-generics/34-type-helpers.problem.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/05-generics/34-generic-props.solution.tsx", - "name": "/src/05-generics/34-generic-props.solution.tsx", + "message": "No test found in suite src/05-generics/34-type-helpers.solution.tsx", + "name": "/src/05-generics/34-type-helpers.solution.tsx", "status": "passed", }, { "assertionResults": [], - "message": "Cannot read properties of null (reading 'useState')", - "name": "/src/05-generics/35-generic-hooks.problem.ts", + "message": "No test found in suite src/05-generics/35-type-helpers-2.problem.tsx", + "name": "/src/05-generics/35-type-helpers-2.problem.tsx", "status": "passed", }, { "assertionResults": [], - "message": "Cannot read properties of null (reading 'useState')", - "name": "/src/05-generics/35-generic-hooks.solution.1.ts", - "status": "passed", - }, - { - "assertionResults": [], - "message": "Cannot read properties of null (reading 'useState')", - "name": "/src/05-generics/35-generic-hooks.solution.2.ts", - "status": "passed", - }, - { - "assertionResults": [], - "message": "Cannot read properties of null (reading 'useState')", - "name": "/src/05-generics/35-generic-hooks.solution.3.ts", - "status": "passed", - }, - { - "assertionResults": [], - "message": "Cannot read properties of null (reading 'useState')", - "name": "/src/05-generics/35-generic-hooks.solution.4.ts", + "message": "No test found in suite src/05-generics/35-type-helpers-2.solution.tsx", + "name": "/src/05-generics/35-type-helpers-2.solution.tsx", "status": "passed", }, { "assertionResults": [], - "message": "Cannot read properties of null (reading 'useState')", - "name": "/src/05-generics/35-generic-hooks.solution.5.ts", + "message": "No test found in suite src/05-generics/36-type-helpers-with-constraints.problem.tsx", + "name": "/src/05-generics/36-type-helpers-with-constraints.problem.tsx", "status": "passed", }, { "assertionResults": [], - "message": "React is not defined", - "name": "/src/05-generics/35.5-generic-class-components.problem.tsx", + "message": "No test found in suite src/05-generics/36-type-helpers-with-constraints.solution.1.tsx", + "name": "/src/05-generics/36-type-helpers-with-constraints.solution.1.tsx", "status": "passed", }, { "assertionResults": [], - "message": "React is not defined", - "name": "/src/05-generics/35.5-generic-class-components.solution.tsx", + "message": "No test found in suite src/05-generics/36-type-helpers-with-constraints.solution.2.tsx", + "name": "/src/05-generics/36-type-helpers-with-constraints.solution.2.tsx", "status": "passed", }, { @@ -762,7 +750,7 @@ exports[`vitest > Should have the correct Vitest errors 1`] = ` }, ], "message": "", - "name": "/src/05-generics/36-generic-localstorage-hook.problem.ts", + "name": "/src/05-generics/37-generic-localstorage-hook.problem.ts", "status": "passed", }, { @@ -787,403 +775,505 @@ exports[`vitest > Should have the correct Vitest errors 1`] = ` }, ], "message": "", - "name": "/src/05-generics/36-generic-localstorage-hook.solution.ts", + "name": "/src/05-generics/37-generic-localstorage-hook.solution.ts", + "status": "passed", + }, + { + "assertionResults": [], + "message": "Cannot read properties of null (reading 'useState')", + "name": "/src/05-generics/38-generic-hooks.problem.ts", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/05-generics/37-generic-inference-through-multiple-helpers.problem.tsx", - "name": "/src/05-generics/37-generic-inference-through-multiple-helpers.problem.tsx", + "message": "Cannot read properties of null (reading 'useState')", + "name": "/src/05-generics/38-generic-hooks.solution.1.ts", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/05-generics/37-generic-inference-through-multiple-helpers.solution.tsx", - "name": "/src/05-generics/37-generic-inference-through-multiple-helpers.solution.tsx", + "message": "Cannot read properties of null (reading 'useState')", + "name": "/src/05-generics/38-generic-hooks.solution.2.ts", "status": "passed", }, { "assertionResults": [], "message": "Cannot read properties of null (reading 'useState')", - "name": "/src/05-generics/37.2-inference-flow-with-constraints.problem.ts", + "name": "/src/05-generics/38-generic-hooks.solution.3.ts", "status": "passed", }, { "assertionResults": [], "message": "Cannot read properties of null (reading 'useState')", - "name": "/src/05-generics/37.2-inference-flow-with-constraints.solution.ts", + "name": "/src/05-generics/38-generic-hooks.solution.4.ts", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/05-generics/37.5-intro-to-const-generics.problem.tsx", - "name": "/src/05-generics/37.5-intro-to-const-generics.problem.tsx", + "message": "Cannot read properties of null (reading 'useState')", + "name": "/src/05-generics/38-generic-hooks.solution.5.ts", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/05-generics/38-button-group.problem.tsx", - "name": "/src/05-generics/38-button-group.problem.tsx", + "message": "No test found in suite src/05-generics/39-generic-props.problem.tsx", + "name": "/src/05-generics/39-generic-props.problem.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/05-generics/38-button-group.solution.1.tsx", - "name": "/src/05-generics/38-button-group.solution.1.tsx", + "message": "No test found in suite src/05-generics/39-generic-props.solution.tsx", + "name": "/src/05-generics/39-generic-props.solution.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/05-generics/38-button-group.solution.2.tsx", - "name": "/src/05-generics/38-button-group.solution.2.tsx", + "message": "React is not defined", + "name": "/src/05-generics/40-generic-class-components.problem.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/05-generics/39-lazy-load-component.problem.tsx", - "name": "/src/05-generics/39-lazy-load-component.problem.tsx", + "message": "React is not defined", + "name": "/src/05-generics/40-generic-class-components.solution.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/05-generics/39-lazy-load-component.solution.tsx", - "name": "/src/05-generics/39-lazy-load-component.solution.tsx", + "message": "No test found in suite src/05-generics/41-passing-types-to-components.problem.tsx", + "name": "/src/05-generics/41-passing-types-to-components.problem.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/05-generics/40-generics-vs-discriminated-unions.problem.tsx", - "name": "/src/05-generics/40-generics-vs-discriminated-unions.problem.tsx", + "message": "No test found in suite src/05-generics/41-passing-types-to-components.solution.tsx", + "name": "/src/05-generics/41-passing-types-to-components.solution.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/05-generics/40-generics-vs-discriminated-unions.solution.tsx", - "name": "/src/05-generics/40-generics-vs-discriminated-unions.solution.tsx", + "message": "No test found in suite src/05-generics/42-generic-inference-through-multiple-helpers.problem.tsx", + "name": "/src/05-generics/42-generic-inference-through-multiple-helpers.problem.tsx", + "status": "passed", + }, + { + "assertionResults": [], + "message": "No test found in suite src/05-generics/42-generic-inference-through-multiple-helpers.solution.tsx", + "name": "/src/05-generics/42-generic-inference-through-multiple-helpers.solution.tsx", + "status": "passed", + }, + { + "assertionResults": [], + "message": "No test found in suite src/05-generics/42-passing-types-to-components.problem.tsx", + "name": "/src/05-generics/42-passing-types-to-components.problem.tsx", "status": "passed", }, { "assertionResults": [], "message": "Cannot read properties of null (reading 'useState')", - "name": "/src/06-advanced-hooks/41-tuple-return-type.problem.ts", + "name": "/src/05-generics/43-inference-flow-with-constraints.problem.ts", "status": "passed", }, { "assertionResults": [], "message": "Cannot read properties of null (reading 'useState')", - "name": "/src/06-advanced-hooks/41-tuple-return-type.solution.1.ts", + "name": "/src/05-generics/43-inference-flow-with-constraints.solution.ts", + "status": "passed", + }, + { + "assertionResults": [], + "message": "No test found in suite src/05-generics/44-generics-vs-discriminated-unions.problem.tsx", + "name": "/src/05-generics/44-generics-vs-discriminated-unions.problem.tsx", + "status": "passed", + }, + { + "assertionResults": [], + "message": "No test found in suite src/05-generics/44-generics-vs-discriminated-unions.solution.tsx", + "name": "/src/05-generics/44-generics-vs-discriminated-unions.solution.tsx", + "status": "passed", + }, + { + "assertionResults": [], + "message": "Cannot read properties of null (reading 'useState')", + "name": "/src/06-advanced-hooks/45-tuple-return-type.problem.ts", "status": "passed", }, { "assertionResults": [], "message": "Cannot read properties of null (reading 'useState')", - "name": "/src/06-advanced-hooks/41-tuple-return-type.solution.2.ts", + "name": "/src/06-advanced-hooks/45-tuple-return-type.solution.1.ts", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/06-advanced-hooks/42-unions-in-usestate.problem.tsx", - "name": "/src/06-advanced-hooks/42-unions-in-usestate.problem.tsx", + "message": "Cannot read properties of null (reading 'useState')", + "name": "/src/06-advanced-hooks/45-tuple-return-type.solution.2.ts", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/06-advanced-hooks/42-unions-in-usestate.solution.tsx", - "name": "/src/06-advanced-hooks/42-unions-in-usestate.solution.tsx", + "message": "No test found in suite src/06-advanced-hooks/46-required-context.problem.tsx", + "name": "/src/06-advanced-hooks/46-required-context.problem.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/06-advanced-hooks/43-discriminated-unions-in-usestate.problem.tsx", - "name": "/src/06-advanced-hooks/43-discriminated-unions-in-usestate.problem.tsx", + "message": "No test found in suite src/06-advanced-hooks/46-required-context.solution.1.tsx", + "name": "/src/06-advanced-hooks/46-required-context.solution.1.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/06-advanced-hooks/43-discriminated-unions-in-usestate.solution.tsx", - "name": "/src/06-advanced-hooks/43-discriminated-unions-in-usestate.solution.tsx", + "message": "No test found in suite src/06-advanced-hooks/46-required-context.solution.2.tsx", + "name": "/src/06-advanced-hooks/46-required-context.solution.2.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/06-advanced-hooks/44-discriminated-tuples-from-custom-hooks.problem.tsx", - "name": "/src/06-advanced-hooks/44-discriminated-tuples-from-custom-hooks.problem.tsx", + "message": "No test found in suite src/06-advanced-hooks/47-unions-in-usestate.problem.tsx", + "name": "/src/06-advanced-hooks/47-unions-in-usestate.problem.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/06-advanced-hooks/44-discriminated-tuples-from-custom-hooks.solution.tsx", - "name": "/src/06-advanced-hooks/44-discriminated-tuples-from-custom-hooks.solution.tsx", + "message": "No test found in suite src/06-advanced-hooks/47-unions-in-usestate.solution.tsx", + "name": "/src/06-advanced-hooks/47-unions-in-usestate.solution.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/06-advanced-hooks/45-use-state-overloads.problem.ts", - "name": "/src/06-advanced-hooks/45-use-state-overloads.problem.ts", + "message": "No test found in suite src/06-advanced-hooks/48-discriminated-unions-in-usestate.problem.tsx", + "name": "/src/06-advanced-hooks/48-discriminated-unions-in-usestate.problem.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/06-advanced-hooks/45-use-state-overloads.solution.1.ts", - "name": "/src/06-advanced-hooks/45-use-state-overloads.solution.1.ts", + "message": "No test found in suite src/06-advanced-hooks/48-discriminated-unions-in-usestate.solution.tsx", + "name": "/src/06-advanced-hooks/48-discriminated-unions-in-usestate.solution.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/06-advanced-hooks/45-use-state-overloads.solution.2.ts", - "name": "/src/06-advanced-hooks/45-use-state-overloads.solution.2.ts", + "message": "No test found in suite src/06-advanced-hooks/49-discriminated-tuples-from-custom-hooks.problem.tsx", + "name": "/src/06-advanced-hooks/49-discriminated-tuples-from-custom-hooks.problem.tsx", + "status": "passed", + }, + { + "assertionResults": [], + "message": "No test found in suite src/06-advanced-hooks/49-discriminated-tuples-from-custom-hooks.solution.tsx", + "name": "/src/06-advanced-hooks/49-discriminated-tuples-from-custom-hooks.solution.tsx", + "status": "passed", + }, + { + "assertionResults": [], + "message": "No test found in suite src/06-advanced-hooks/50-use-state-overloads.problem.ts", + "name": "/src/06-advanced-hooks/50-use-state-overloads.problem.ts", + "status": "passed", + }, + { + "assertionResults": [], + "message": "No test found in suite src/06-advanced-hooks/50-use-state-overloads.solution.1.ts", + "name": "/src/06-advanced-hooks/50-use-state-overloads.solution.1.ts", + "status": "passed", + }, + { + "assertionResults": [], + "message": "No test found in suite src/06-advanced-hooks/50-use-state-overloads.solution.2.ts", + "name": "/src/06-advanced-hooks/50-use-state-overloads.solution.2.ts", "status": "passed", }, { "assertionResults": [], "message": "Cannot read properties of null (reading 'useState')", - "name": "/src/06-advanced-hooks/46-function-overloads-in-hooks.problem.ts", + "name": "/src/06-advanced-hooks/51-function-overloads-in-hooks.problem.ts", "status": "passed", }, { "assertionResults": [], "message": "Cannot read properties of null (reading 'useState')", - "name": "/src/06-advanced-hooks/46-function-overloads-in-hooks.solution.1.ts", + "name": "/src/06-advanced-hooks/51-function-overloads-in-hooks.solution.1.ts", "status": "passed", }, { "assertionResults": [], "message": "Cannot read properties of null (reading 'useState')", - "name": "/src/06-advanced-hooks/46-function-overloads-in-hooks.solution.2.ts", + "name": "/src/06-advanced-hooks/51-function-overloads-in-hooks.solution.2.ts", + "status": "passed", + }, + { + "assertionResults": [], + "message": "No test found in suite src/06-advanced-hooks/52-currying-hooks.problem.ts", + "name": "/src/06-advanced-hooks/52-currying-hooks.problem.ts", + "status": "passed", + }, + { + "assertionResults": [], + "message": "No test found in suite src/06-advanced-hooks/52-currying-hooks.solution.ts", + "name": "/src/06-advanced-hooks/52-currying-hooks.solution.ts", + "status": "passed", + }, + { + "assertionResults": [], + "message": "React is not defined", + "name": "/src/07-types-deep-dive/53-understand-react-namespace-export.explainer.ts", + "status": "passed", + }, + { + "assertionResults": [], + "message": "No test found in suite src/07-types-deep-dive/54-understanding-jsx-element.explainer.tsx", + "name": "/src/07-types-deep-dive/54-understanding-jsx-element.explainer.tsx", + "status": "passed", + }, + { + "assertionResults": [], + "message": "No test found in suite src/07-types-deep-dive/55-strongly-typing-children.explainer.tsx", + "name": "/src/07-types-deep-dive/55-strongly-typing-children.explainer.tsx", + "status": "passed", + }, + { + "assertionResults": [], + "message": "No test found in suite src/07-types-deep-dive/56-understanding-jsx-intrinsic-elements.explainer.tsx", + "name": "/src/07-types-deep-dive/56-understanding-jsx-intrinsic-elements.explainer.tsx", "status": "passed", }, { "assertionResults": [], "message": "React is not defined", - "name": "/src/07-types-deep-dive/47-understand-react-namespace-export.explainer.ts", + "name": "/src/07-types-deep-dive/57-react-component-type.explainer.tsx", + "status": "passed", + }, + { + "assertionResults": [], + "message": "No test found in suite src/07-types-deep-dive/58-appending-to-global-namespace.problem.ts", + "name": "/src/07-types-deep-dive/58-appending-to-global-namespace.problem.ts", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/07-types-deep-dive/48-understanding-jsx-element.explainer.tsx", - "name": "/src/07-types-deep-dive/48-understanding-jsx-element.explainer.tsx", + "message": "No test found in suite src/07-types-deep-dive/58-appending-to-global-namespace.solution.ts", + "name": "/src/07-types-deep-dive/58-appending-to-global-namespace.solution.ts", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/07-types-deep-dive/49-strongly-typing-children.explainer.tsx", - "name": "/src/07-types-deep-dive/49-strongly-typing-children.explainer.tsx", + "message": "No test found in suite src/07-types-deep-dive/59-declaration-merging-in-global-namespace.problem.ts", + "name": "/src/07-types-deep-dive/59-declaration-merging-in-global-namespace.problem.ts", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/07-types-deep-dive/50-understanding-jsx-intrinsic-elements.explainer.tsx", - "name": "/src/07-types-deep-dive/50-understanding-jsx-intrinsic-elements.explainer.tsx", + "message": "No test found in suite src/07-types-deep-dive/59-declaration-merging-in-global-namespace.solution.ts", + "name": "/src/07-types-deep-dive/59-declaration-merging-in-global-namespace.solution.ts", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/07-types-deep-dive/51-appending-to-global-namespace.problem.ts", - "name": "/src/07-types-deep-dive/51-appending-to-global-namespace.problem.ts", + "message": "No test found in suite src/07-types-deep-dive/60-add-new-global-element.problem.tsx", + "name": "/src/07-types-deep-dive/60-add-new-global-element.problem.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/07-types-deep-dive/51-appending-to-global-namespace.solution.ts", - "name": "/src/07-types-deep-dive/51-appending-to-global-namespace.solution.ts", + "message": "No test found in suite src/07-types-deep-dive/60-add-new-global-element.solution.tsx", + "name": "/src/07-types-deep-dive/60-add-new-global-element.solution.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/07-types-deep-dive/52-declaration-merging-in-global-namespace.problem.ts", - "name": "/src/07-types-deep-dive/52-declaration-merging-in-global-namespace.problem.ts", + "message": "No test found in suite src/07-types-deep-dive/61-html-attributes.explainer.tsx", + "name": "/src/07-types-deep-dive/61-html-attributes.explainer.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/07-types-deep-dive/52-declaration-merging-in-global-namespace.solution.ts", - "name": "/src/07-types-deep-dive/52-declaration-merging-in-global-namespace.solution.ts", + "message": "No test found in suite src/07-types-deep-dive/62-add-attribute-to-all-elements.problem.tsx", + "name": "/src/07-types-deep-dive/62-add-attribute-to-all-elements.problem.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/07-types-deep-dive/53-add-new-global-element.problem.tsx", - "name": "/src/07-types-deep-dive/53-add-new-global-element.problem.tsx", + "message": "No test found in suite src/07-types-deep-dive/62-add-attribute-to-all-elements.solution.tsx", + "name": "/src/07-types-deep-dive/62-add-attribute-to-all-elements.solution.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/07-types-deep-dive/53-add-new-global-element.solution.tsx", - "name": "/src/07-types-deep-dive/53-add-new-global-element.solution.tsx", + "message": "No test found in suite src/08-advanced-patterns/63-lazy-load-component.problem.tsx", + "name": "/src/08-advanced-patterns/63-lazy-load-component.problem.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/07-types-deep-dive/54-html-attributes.explainer.tsx", - "name": "/src/07-types-deep-dive/54-html-attributes.explainer.tsx", + "message": "No test found in suite src/08-advanced-patterns/63-lazy-load-component.solution.tsx", + "name": "/src/08-advanced-patterns/63-lazy-load-component.solution.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/07-types-deep-dive/55-add-attribute-to-all-elements.problem.tsx", - "name": "/src/07-types-deep-dive/55-add-attribute-to-all-elements.problem.tsx", + "message": "No test found in suite src/08-advanced-patterns/64-const-generics-in-generic-components.problem.tsx", + "name": "/src/08-advanced-patterns/64-const-generics-in-generic-components.problem.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/07-types-deep-dive/55-add-attribute-to-all-elements.solution.tsx", - "name": "/src/07-types-deep-dive/55-add-attribute-to-all-elements.solution.tsx", + "message": "No test found in suite src/08-advanced-patterns/65-render-props.problem.tsx", + "name": "/src/08-advanced-patterns/65-render-props.problem.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/08-advanced-patterns/56-required-context.problem.tsx", - "name": "/src/08-advanced-patterns/56-required-context.problem.tsx", + "message": "No test found in suite src/08-advanced-patterns/65-render-props.solution.tsx", + "name": "/src/08-advanced-patterns/65-render-props.solution.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/08-advanced-patterns/56-required-context.solution.1.tsx", - "name": "/src/08-advanced-patterns/56-required-context.solution.1.tsx", + "message": "No test found in suite src/08-advanced-patterns/66-forward-ref-with-generics.explainer.1.tsx", + "name": "/src/08-advanced-patterns/66-forward-ref-with-generics.explainer.1.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/08-advanced-patterns/56-required-context.solution.2.tsx", - "name": "/src/08-advanced-patterns/56-required-context.solution.2.tsx", + "message": "No test found in suite src/08-advanced-patterns/66-forward-ref-with-generics.explainer.2.tsx", + "name": "/src/08-advanced-patterns/66-forward-ref-with-generics.explainer.2.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/08-advanced-patterns/57-render-props.problem.tsx", - "name": "/src/08-advanced-patterns/57-render-props.problem.tsx", + "message": "No test found in suite src/08-advanced-patterns/66-forward-ref-with-generics.explainer.3.ts", + "name": "/src/08-advanced-patterns/66-forward-ref-with-generics.explainer.3.ts", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/08-advanced-patterns/57-render-props.solution.tsx", - "name": "/src/08-advanced-patterns/57-render-props.solution.tsx", + "message": "No test found in suite src/08-advanced-patterns/67-forward-ref-as-local-function.problem.tsx", + "name": "/src/08-advanced-patterns/67-forward-ref-as-local-function.problem.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/08-advanced-patterns/58-forward-ref-with-generics.explainer.1.tsx", - "name": "/src/08-advanced-patterns/58-forward-ref-with-generics.explainer.1.tsx", + "message": "No test found in suite src/08-advanced-patterns/67-forward-ref-as-local-function.solution.tsx", + "name": "/src/08-advanced-patterns/67-forward-ref-as-local-function.solution.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/08-advanced-patterns/58-forward-ref-with-generics.explainer.2.tsx", - "name": "/src/08-advanced-patterns/58-forward-ref-with-generics.explainer.2.tsx", + "message": "No test found in suite src/08-advanced-patterns/68-hoc.problem.tsx", + "name": "/src/08-advanced-patterns/68-hoc.problem.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/08-advanced-patterns/58-forward-ref-with-generics.explainer.3.ts", - "name": "/src/08-advanced-patterns/58-forward-ref-with-generics.explainer.3.ts", + "message": "No test found in suite src/08-advanced-patterns/68-hoc.solution.tsx", + "name": "/src/08-advanced-patterns/68-hoc.solution.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/08-advanced-patterns/59-hoc.problem.tsx", - "name": "/src/08-advanced-patterns/59-hoc.problem.tsx", + "message": "No test found in suite src/08-advanced-patterns/69-record-of-components-with-same-props.problem.tsx", + "name": "/src/08-advanced-patterns/69-record-of-components-with-same-props.problem.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/08-advanced-patterns/59-hoc.solution.tsx", - "name": "/src/08-advanced-patterns/59-hoc.solution.tsx", + "message": "No test found in suite src/08-advanced-patterns/69-record-of-components-with-same-props.solution.1.tsx", + "name": "/src/08-advanced-patterns/69-record-of-components-with-same-props.solution.1.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/08-advanced-patterns/60-record-of-components-with-same-props.problem.tsx", - "name": "/src/08-advanced-patterns/60-record-of-components-with-same-props.problem.tsx", + "message": "No test found in suite src/08-advanced-patterns/69-record-of-components-with-same-props.solution.2.tsx", + "name": "/src/08-advanced-patterns/69-record-of-components-with-same-props.solution.2.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/08-advanced-patterns/60-record-of-components-with-same-props.solution.1.tsx", - "name": "/src/08-advanced-patterns/60-record-of-components-with-same-props.solution.1.tsx", + "message": "No test found in suite src/08-advanced-patterns/70-as-prop.problem.tsx", + "name": "/src/08-advanced-patterns/70-as-prop.problem.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/08-advanced-patterns/60-record-of-components-with-same-props.solution.2.tsx", - "name": "/src/08-advanced-patterns/60-record-of-components-with-same-props.solution.2.tsx", + "message": "No test found in suite src/08-advanced-patterns/70-as-prop.solution.1.tsx", + "name": "/src/08-advanced-patterns/70-as-prop.solution.1.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/08-advanced-patterns/61-as-prop.problem.tsx", - "name": "/src/08-advanced-patterns/61-as-prop.problem.tsx", + "message": "No test found in suite src/08-advanced-patterns/70-as-prop.solution.2.tsx", + "name": "/src/08-advanced-patterns/70-as-prop.solution.2.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/08-advanced-patterns/61-as-prop.solution.1.tsx", - "name": "/src/08-advanced-patterns/61-as-prop.solution.1.tsx", + "message": "No test found in suite src/08-advanced-patterns/71-as-prop-with-custom-components.problem.tsx", + "name": "/src/08-advanced-patterns/71-as-prop-with-custom-components.problem.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/08-advanced-patterns/61-as-prop.solution.2.tsx", - "name": "/src/08-advanced-patterns/61-as-prop.solution.2.tsx", + "message": "No test found in suite src/08-advanced-patterns/71-as-prop-with-custom-components.solution.tsx", + "name": "/src/08-advanced-patterns/71-as-prop-with-custom-components.solution.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/08-advanced-patterns/62-as-prop-with-custom-components.problem.tsx", - "name": "/src/08-advanced-patterns/62-as-prop-with-custom-components.problem.tsx", + "message": "No test found in suite src/08-advanced-patterns/72-as-prop-with-default.problem.tsx", + "name": "/src/08-advanced-patterns/72-as-prop-with-default.problem.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/08-advanced-patterns/62-as-prop-with-custom-components.solution.tsx", - "name": "/src/08-advanced-patterns/62-as-prop-with-custom-components.solution.tsx", + "message": "No test found in suite src/08-advanced-patterns/72-as-prop-with-default.solution.tsx", + "name": "/src/08-advanced-patterns/72-as-prop-with-default.solution.tsx", "status": "passed", }, { "assertionResults": [], "message": "Cannot read properties of null (reading 'useRef')", - "name": "/src/09-external-libraries/63-react-hook-form.explainer.tsx", + "name": "/src/09-external-libraries/73-react-hook-form.explainer.tsx", "status": "passed", }, { "assertionResults": [], "message": "Cannot read properties of null (reading 'useRef')", - "name": "/src/09-external-libraries/64-react-hook-form-wrapper.problem.tsx", + "name": "/src/09-external-libraries/74-react-hook-form-wrapper.problem.tsx", "status": "passed", }, { "assertionResults": [], "message": "Cannot read properties of null (reading 'useRef')", - "name": "/src/09-external-libraries/64-react-hook-form-wrapper.solution.tsx", + "name": "/src/09-external-libraries/74-react-hook-form-wrapper.solution.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/09-external-libraries/65-react-select.problem.tsx", - "name": "/src/09-external-libraries/65-react-select.problem.tsx", + "message": "No test found in suite src/09-external-libraries/75-react-select.problem.tsx", + "name": "/src/09-external-libraries/75-react-select.problem.tsx", "status": "passed", }, { "assertionResults": [], - "message": "No test found in suite src/09-external-libraries/65-react-select.solution.tsx", - "name": "/src/09-external-libraries/65-react-select.solution.tsx", + "message": "No test found in suite src/09-external-libraries/75-react-select.solution.tsx", + "name": "/src/09-external-libraries/75-react-select.solution.tsx", "status": "passed", }, { "assertionResults": [], "message": "Cannot read properties of null (reading 'useContext')", - "name": "/src/09-external-libraries/66-react-query.explainer.ts", + "name": "/src/09-external-libraries/76-react-query.explainer.ts", "status": "passed", }, { "assertionResults": [], "message": "Cannot read properties of null (reading 'useContext')", - "name": "/src/09-external-libraries/67-react-query-wrapper.problem.ts", + "name": "/src/09-external-libraries/77-react-query-wrapper.problem.ts", "status": "passed", }, { "assertionResults": [], "message": "Cannot read properties of null (reading 'useContext')", - "name": "/src/09-external-libraries/67-react-query-wrapper.solution.ts", + "name": "/src/09-external-libraries/77-react-query-wrapper.solution.ts", "status": "passed", }, ], From d4f97d26da9e9f24f3d854d42b396a558eff02c2 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 17 Jul 2023 10:50:27 +0100 Subject: [PATCH 013/105] Added moduleDetection: force --- tsconfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/tsconfig.json b/tsconfig.json index d9a0299..9495bf4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,6 +6,7 @@ "moduleResolution": "node", "noEmit": true, "isolatedModules": true, + "moduleDetection": "force", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, From 0b18aed1f6a277bc601ce9daa7a25448718795be Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 17 Jul 2023 13:58:16 +0100 Subject: [PATCH 014/105] Added export to 53 --- .../53-understand-react-namespace-export.explainer.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/07-types-deep-dive/53-understand-react-namespace-export.explainer.ts b/src/07-types-deep-dive/53-understand-react-namespace-export.explainer.ts index 824b115..b842aa4 100644 --- a/src/07-types-deep-dive/53-understand-react-namespace-export.explainer.ts +++ b/src/07-types-deep-dive/53-understand-react-namespace-export.explainer.ts @@ -3,6 +3,7 @@ */ // 1. What is the React namespace? +// 1a. Why can it be accessed globally as a type? type Example = React.ReactNode; // ^? @@ -16,3 +17,5 @@ type Example = React.ReactNode; */ const element = React.createElement("div"); // ^? + +export {}; From e28e9d53d77da61bb5fc29f1d0fcec27cbbfe00e Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 17 Jul 2023 14:07:06 +0100 Subject: [PATCH 015/105] Added problem/solution --- ...erstand-react-namespace-export.problem.ts} | 0 ...erstand-react-namespace-export.solution.ts | 21 +++++++++++++++++++ 2 files changed, 21 insertions(+) rename src/07-types-deep-dive/{53-understand-react-namespace-export.explainer.ts => 53-understand-react-namespace-export.problem.ts} (100%) create mode 100644 src/07-types-deep-dive/53-understand-react-namespace-export.solution.ts diff --git a/src/07-types-deep-dive/53-understand-react-namespace-export.explainer.ts b/src/07-types-deep-dive/53-understand-react-namespace-export.problem.ts similarity index 100% rename from src/07-types-deep-dive/53-understand-react-namespace-export.explainer.ts rename to src/07-types-deep-dive/53-understand-react-namespace-export.problem.ts diff --git a/src/07-types-deep-dive/53-understand-react-namespace-export.solution.ts b/src/07-types-deep-dive/53-understand-react-namespace-export.solution.ts new file mode 100644 index 0000000..b842aa4 --- /dev/null +++ b/src/07-types-deep-dive/53-understand-react-namespace-export.solution.ts @@ -0,0 +1,21 @@ +/** + * Questions to answer: + */ + +// 1. What is the React namespace? +// 1a. Why can it be accessed globally as a type? +type Example = React.ReactNode; +// ^? + +/** + * 2a. Most namespaces can't be used as values. So how come + * we can use React as a value here? + * + * HINT - we're adding LOTS of things to React's namespace in + * later exercises, so make sure when you go-to-definition you + * go to its original definition, in @types/react/index.d.ts. + */ +const element = React.createElement("div"); +// ^? + +export {}; From 47a7581eb15f18b4e64e819fb18d5fcb03ce53c1 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 17 Jul 2023 14:51:36 +0100 Subject: [PATCH 016/105] Updated snappyshotties --- scripts/tests/__snapshots__/all.test.ts.snap | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/tests/__snapshots__/all.test.ts.snap b/scripts/tests/__snapshots__/all.test.ts.snap index 35cfd0f..c8ff6f7 100644 --- a/scripts/tests/__snapshots__/all.test.ts.snap +++ b/scripts/tests/__snapshots__/all.test.ts.snap @@ -1015,7 +1015,13 @@ exports[`vitest > Should have the correct Vitest errors 1`] = ` { "assertionResults": [], "message": "React is not defined", - "name": "/src/07-types-deep-dive/53-understand-react-namespace-export.explainer.ts", + "name": "/src/07-types-deep-dive/53-understand-react-namespace-export.problem.ts", + "status": "passed", + }, + { + "assertionResults": [], + "message": "React is not defined", + "name": "/src/07-types-deep-dive/53-understand-react-namespace-export.solution.ts", "status": "passed", }, { From 47582330c72bb6c717a721535a8471998d3472d2 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 17 Jul 2023 14:57:23 +0100 Subject: [PATCH 017/105] Fixed 53 --- .../53-understand-react-namespace-export.problem.ts | 6 +++--- .../53-understand-react-namespace-export.solution.ts | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/07-types-deep-dive/53-understand-react-namespace-export.problem.ts b/src/07-types-deep-dive/53-understand-react-namespace-export.problem.ts index b842aa4..9ef28a5 100644 --- a/src/07-types-deep-dive/53-understand-react-namespace-export.problem.ts +++ b/src/07-types-deep-dive/53-understand-react-namespace-export.problem.ts @@ -1,15 +1,15 @@ +import React from "react"; + /** * Questions to answer: */ // 1. What is the React namespace? -// 1a. Why can it be accessed globally as a type? type Example = React.ReactNode; // ^? /** - * 2a. Most namespaces can't be used as values. So how come - * we can use React as a value here? + * 2. How come React can be used BOTH as a value and a type? * * HINT - we're adding LOTS of things to React's namespace in * later exercises, so make sure when you go-to-definition you diff --git a/src/07-types-deep-dive/53-understand-react-namespace-export.solution.ts b/src/07-types-deep-dive/53-understand-react-namespace-export.solution.ts index b842aa4..9ef28a5 100644 --- a/src/07-types-deep-dive/53-understand-react-namespace-export.solution.ts +++ b/src/07-types-deep-dive/53-understand-react-namespace-export.solution.ts @@ -1,15 +1,15 @@ +import React from "react"; + /** * Questions to answer: */ // 1. What is the React namespace? -// 1a. Why can it be accessed globally as a type? type Example = React.ReactNode; // ^? /** - * 2a. Most namespaces can't be used as values. So how come - * we can use React as a value here? + * 2. How come React can be used BOTH as a value and a type? * * HINT - we're adding LOTS of things to React's namespace in * later exercises, so make sure when you go-to-definition you From 591fe3092a396ed312ce661c9c6c7ad5b63ced35 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 17 Jul 2023 15:05:36 +0100 Subject: [PATCH 018/105] Added problem/solution to 54 --- ... 54-understanding-jsx-element.problem.tsx} | 0 .../54-understanding-jsx-element.solution.tsx | 53 +++++++++++++++++++ 2 files changed, 53 insertions(+) rename src/07-types-deep-dive/{54-understanding-jsx-element.explainer.tsx => 54-understanding-jsx-element.problem.tsx} (100%) create mode 100644 src/07-types-deep-dive/54-understanding-jsx-element.solution.tsx diff --git a/src/07-types-deep-dive/54-understanding-jsx-element.explainer.tsx b/src/07-types-deep-dive/54-understanding-jsx-element.problem.tsx similarity index 100% rename from src/07-types-deep-dive/54-understanding-jsx-element.explainer.tsx rename to src/07-types-deep-dive/54-understanding-jsx-element.problem.tsx diff --git a/src/07-types-deep-dive/54-understanding-jsx-element.solution.tsx b/src/07-types-deep-dive/54-understanding-jsx-element.solution.tsx new file mode 100644 index 0000000..6b8506f --- /dev/null +++ b/src/07-types-deep-dive/54-understanding-jsx-element.solution.tsx @@ -0,0 +1,53 @@ +/** + * 1. What's the difference between JSX.Element, + * React.ReactNode and React.ReactElement? + * + * CMD-click each of them to understand the difference. + */ + +type ClickMe = React.ReactElement; +type ClickMeToo = JSX.Element; +type ClickMeThree = React.ReactNode; + +/** + * 2. What is the return type of this Component? + */ +const Component = () => { + return

Hello world
; +}; + +/** + * 3. Fun fact - this might break on your IDE! In + * TypeScript 5.0, this wouldn't work. But in TypeScript + * 5.1, it DOES work. + * + * If it's not working for you, try making your IDE use + * the 'workspace' version of TypeScript. + * + * https://stackoverflow.com/questions/39668731/what-typescript-version-is-visual-studio-code-using-how-to-update-it + */ +const Component2 = (): React.ReactNode => { + return
; +}; + +<> + +; + +/** + * 4a. Why does this component NOT error... + */ +const Component3 = (): React.ReactElement => { + return
; +}; + +<> + +; + +/** + * 4b. ...but this one does? + */ +const Component4 = (): React.ReactElement => { + return "hello!"; +}; From 952cc4e495694264cba0e8a907d820d31b9eee76 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 17 Jul 2023 15:22:04 +0100 Subject: [PATCH 019/105] P/S'd 55 --- ...> 55-strongly-typing-children.problem.tsx} | 0 .../55-strongly-typing-children.solution.tsx | 33 +++++++++++++++++++ 2 files changed, 33 insertions(+) rename src/07-types-deep-dive/{55-strongly-typing-children.explainer.tsx => 55-strongly-typing-children.problem.tsx} (100%) create mode 100644 src/07-types-deep-dive/55-strongly-typing-children.solution.tsx diff --git a/src/07-types-deep-dive/55-strongly-typing-children.explainer.tsx b/src/07-types-deep-dive/55-strongly-typing-children.problem.tsx similarity index 100% rename from src/07-types-deep-dive/55-strongly-typing-children.explainer.tsx rename to src/07-types-deep-dive/55-strongly-typing-children.problem.tsx diff --git a/src/07-types-deep-dive/55-strongly-typing-children.solution.tsx b/src/07-types-deep-dive/55-strongly-typing-children.solution.tsx new file mode 100644 index 0000000..1a89bd9 --- /dev/null +++ b/src/07-types-deep-dive/55-strongly-typing-children.solution.tsx @@ -0,0 +1,33 @@ +import { ReactNode } from "react"; + +/** + * In this example we have a Select component. Through some magic, we're + * attempting to strongly type the children of the Select component so + * that you can only pass 'Option' elements to it. + * + * 1. Try to understand the type of OptionType. What's the __brand property + * for? + * + * 2. There's an error happening at ) as OptionType; +}; + +const Select = (props: { children: OptionType }) => { + return ; +}; + +; From 02fcb37753ee0bcdd5aa84669f23110d18335520 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 17 Jul 2023 15:26:30 +0100 Subject: [PATCH 020/105] P/S --- ...anding-jsx-intrinsic-elements.problem.tsx} | 0 ...anding-jsx-intrinsic-elements.solution.tsx | 30 +++++++++++++++++++ 2 files changed, 30 insertions(+) rename src/07-types-deep-dive/{56-understanding-jsx-intrinsic-elements.explainer.tsx => 56-understanding-jsx-intrinsic-elements.problem.tsx} (100%) create mode 100644 src/07-types-deep-dive/56-understanding-jsx-intrinsic-elements.solution.tsx diff --git a/src/07-types-deep-dive/56-understanding-jsx-intrinsic-elements.explainer.tsx b/src/07-types-deep-dive/56-understanding-jsx-intrinsic-elements.problem.tsx similarity index 100% rename from src/07-types-deep-dive/56-understanding-jsx-intrinsic-elements.explainer.tsx rename to src/07-types-deep-dive/56-understanding-jsx-intrinsic-elements.problem.tsx diff --git a/src/07-types-deep-dive/56-understanding-jsx-intrinsic-elements.solution.tsx b/src/07-types-deep-dive/56-understanding-jsx-intrinsic-elements.solution.tsx new file mode 100644 index 0000000..49419fe --- /dev/null +++ b/src/07-types-deep-dive/56-understanding-jsx-intrinsic-elements.solution.tsx @@ -0,0 +1,30 @@ +/** + * 1. What is JSX.IntrinsicElements? CMD-click on .IntrinsicElements below + * to go to its definition. + * + * Hint - remember to go to the original definition of JSX.IntrinsicElements + * in @types/react/index.d.ts. + */ + +export type Example = JSX.IntrinsicElements; + +/** + * 2. What is the structure of JSX.IntrinsicElements? It appears to have the + * HTML attributes as properties, but what are the values? + * + * 3. Let's have some fun. Edit the file to add a new property to + * JSX.IntrinsicElements: + * + * interface IntrinsicElements { + * // ... + * myNewElement: { + * foo: string; + * } + * } + * + * Notice that the error below goes away! + * + * 4. Now change it back, before anyone notices. + */ + +; From 635d87c5585541d1b9eebdc01c51e072c5b4594e Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 17 Jul 2023 15:52:18 +0100 Subject: [PATCH 021/105] Fixed 60 description --- src/07-types-deep-dive/60-add-new-global-element.problem.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/07-types-deep-dive/60-add-new-global-element.problem.tsx b/src/07-types-deep-dive/60-add-new-global-element.problem.tsx index d4241d3..a0b763d 100644 --- a/src/07-types-deep-dive/60-add-new-global-element.problem.tsx +++ b/src/07-types-deep-dive/60-add-new-global-element.problem.tsx @@ -7,7 +7,7 @@ * which takes a required `id` attribute. * * Hint - you'll need to declaration merge with an existing - * interface in the React namespace. + * interface in the JSX namespace. */ <> From ac5e74fffb4f16e98d1ac305f56e3c91097dd8a7 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 17 Jul 2023 15:57:21 +0100 Subject: [PATCH 022/105] P/S --- ...ner.tsx => 61-html-attributes.problem.tsx} | 0 .../61-html-attributes.solution.tsx | 24 +++++++++++++++++++ 2 files changed, 24 insertions(+) rename src/07-types-deep-dive/{61-html-attributes.explainer.tsx => 61-html-attributes.problem.tsx} (100%) create mode 100644 src/07-types-deep-dive/61-html-attributes.solution.tsx diff --git a/src/07-types-deep-dive/61-html-attributes.explainer.tsx b/src/07-types-deep-dive/61-html-attributes.problem.tsx similarity index 100% rename from src/07-types-deep-dive/61-html-attributes.explainer.tsx rename to src/07-types-deep-dive/61-html-attributes.problem.tsx diff --git a/src/07-types-deep-dive/61-html-attributes.solution.tsx b/src/07-types-deep-dive/61-html-attributes.solution.tsx new file mode 100644 index 0000000..77c80da --- /dev/null +++ b/src/07-types-deep-dive/61-html-attributes.solution.tsx @@ -0,0 +1,24 @@ +/** + * 1. How does React know which HTML attributes can be passed + * to each HTML element? + * + * On which interfaces/types are they stored? + */ + +/** + * 2. Try CMD-clicking on the 'div' below. What information + * does that give you? + */ +
; + +/** + * 3. Try CMD-clicking on the className prop below. What + * interface does it lead you to? + */ +
; + +/** + * 4. Finally, try CMD-clicking on the 'href' prop below. + * What interface does it lead you to? + */ +; From 704e257fa6a3a8d8ebd757ac4c1dddb9a671ede2 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 24 Jul 2023 11:09:01 +0100 Subject: [PATCH 023/105] WIP --- ...ward-ref-as-local-function.solution.1.tsx} | 0 ...rward-ref-as-local-function.solution.2.tsx | 32 +++++++++++ .../72.5-as-prop-with-forward-ref.problem.tsx | 37 ++++++++++++ ...72.5-as-prop-with-forward-ref.solution.tsx | 57 +++++++++++++++++++ 4 files changed, 126 insertions(+) rename src/08-advanced-patterns/{67-forward-ref-as-local-function.solution.tsx => 67-forward-ref-as-local-function.solution.1.tsx} (100%) create mode 100644 src/08-advanced-patterns/67-forward-ref-as-local-function.solution.2.tsx create mode 100644 src/08-advanced-patterns/72.5-as-prop-with-forward-ref.problem.tsx create mode 100644 src/08-advanced-patterns/72.5-as-prop-with-forward-ref.solution.tsx diff --git a/src/08-advanced-patterns/67-forward-ref-as-local-function.solution.tsx b/src/08-advanced-patterns/67-forward-ref-as-local-function.solution.1.tsx similarity index 100% rename from src/08-advanced-patterns/67-forward-ref-as-local-function.solution.tsx rename to src/08-advanced-patterns/67-forward-ref-as-local-function.solution.1.tsx diff --git a/src/08-advanced-patterns/67-forward-ref-as-local-function.solution.2.tsx b/src/08-advanced-patterns/67-forward-ref-as-local-function.solution.2.tsx new file mode 100644 index 0000000..37ae3f0 --- /dev/null +++ b/src/08-advanced-patterns/67-forward-ref-as-local-function.solution.2.tsx @@ -0,0 +1,32 @@ +import { Equal, Expect } from "../helpers/type-utils"; + +import { ForwardedRef, forwardRef } from "react"; + +type FixedForwardRef = ( + render: (props: P, ref: React.Ref) => React.ReactNode, +) => (props: P & React.RefAttributes) => React.ReactNode; + +const fixedForwardRef = forwardRef as FixedForwardRef; + +type Props = { + data: T[]; + renderRow: (item: T) => React.ReactNode; +}; + +export const Table = (props: Props, ref: ForwardedRef) => { + return null; +}; + +const ForwardReffedTable = fixedForwardRef(Table); + +const Parent = () => { + return ( + { + type test = Expect>; + return
123
; + }} + >
+ ); +}; diff --git a/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.problem.tsx b/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.problem.tsx new file mode 100644 index 0000000..fd330b7 --- /dev/null +++ b/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.problem.tsx @@ -0,0 +1,37 @@ +import { ComponentPropsWithoutRef, ElementType, forwardRef } from "react"; +import { Equal, Expect } from "../helpers/type-utils"; + +export const Link = forwardRef( + = "a">( + props: { + as?: T; + } & ComponentPropsWithoutRef, + ) => { + const { as: Comp = "a", ...rest } = props; + return ; + }, +); + +; + +const Custom = (props: { thisIsRequired: boolean }) => { + return null; +}; + +; + +// @ts-expect-error Property 'thisIsRequired' is missing +; + + { + type test = Expect>>; + }} +>; + +; diff --git a/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.solution.tsx b/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.solution.tsx new file mode 100644 index 0000000..33cd7e9 --- /dev/null +++ b/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.solution.tsx @@ -0,0 +1,57 @@ +import { + ComponentProps, + ComponentPropsWithoutRef, + ElementType, + forwardRef, + useRef, +} from "react"; +import { Equal, Expect } from "../helpers/type-utils"; + +type FixedForwardRef = ( + render: (props: P, ref: React.Ref) => React.ReactNode, +) => (props: P & React.RefAttributes) => React.ReactNode; + +const fixedForwardRef = forwardRef as FixedForwardRef; + +export const Link = fixedForwardRef( + ( + props: { + as?: T; + } & ComponentProps, + ) => { + const { as = "a", ...rest } = props; + const Comp = as as any; + return ; + }, +); + +const Test = () => { + const ref = useRef(null); + + return ; +}; + +const Custom = (props: { thisIsRequired: boolean }) => { + return null; +}; + +; + +// @ts-expect-error Property 'thisIsRequired' is missing +; + +const ref = useRef(null); + + { + type test = Expect>>; + }} + ref={ref} +>; + +; From 757f4c5cf60e42f52460a00d6accc7a74701acf4 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 24 Jul 2023 11:12:16 +0100 Subject: [PATCH 024/105] Changed ElementType --- scripts/tests/__snapshots__/all.test.ts.snap | 2 +- .../71-as-prop-with-custom-components.solution.tsx | 2 +- src/08-advanced-patterns/72-as-prop-with-default.problem.tsx | 2 +- src/08-advanced-patterns/72-as-prop-with-default.solution.tsx | 2 +- .../72.5-as-prop-with-forward-ref.problem.tsx | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/tests/__snapshots__/all.test.ts.snap b/scripts/tests/__snapshots__/all.test.ts.snap index c8ff6f7..a1f75ec 100644 --- a/scripts/tests/__snapshots__/all.test.ts.snap +++ b/scripts/tests/__snapshots__/all.test.ts.snap @@ -211,7 +211,7 @@ src/08-advanced-patterns/71-as-prop-with-custom-components.problem.tsx(21,20): e Property 'href' does not exist on type 'IntrinsicAttributes & { as: unknown; }'. src/08-advanced-patterns/72-as-prop-with-default.problem.tsx(10,11): error TS2322: Type 'Omit<{ as: T; } & ComponentPropsWithoutRef, \\"as\\">' is not assignable to type 'IntrinsicAttributes & LibraryManagedAttributes'. Type 'Omit<{ as: T; } & ComponentPropsWithoutRef, \\"as\\">' is not assignable to type 'LibraryManagedAttributes'. -src/08-advanced-patterns/72-as-prop-with-default.problem.tsx(14,2): error TS2741: Property 'as' is missing in type '{ href: string; }' but required in type '{ as: ElementType; }'. +src/08-advanced-patterns/72-as-prop-with-default.problem.tsx(14,2): error TS2741: Property 'as' is missing in type '{ href: string; }' but required in type '{ as: ElementType; }'. src/09-external-libraries/74-react-hook-form-wrapper.problem.tsx(29,3): error TS2578: Unused '@ts-expect-error' directive. src/09-external-libraries/74-react-hook-form-wrapper.problem.tsx(42,5): error TS2344: Type 'boolean' does not satisfy the constraint 'true'. src/09-external-libraries/75-react-select.problem.tsx(10,24): error TS7006: Parameter 'props' implicitly has an 'any' type. diff --git a/src/08-advanced-patterns/71-as-prop-with-custom-components.solution.tsx b/src/08-advanced-patterns/71-as-prop-with-custom-components.solution.tsx index 6af9b70..fe09d73 100644 --- a/src/08-advanced-patterns/71-as-prop-with-custom-components.solution.tsx +++ b/src/08-advanced-patterns/71-as-prop-with-custom-components.solution.tsx @@ -1,7 +1,7 @@ import React, { ComponentPropsWithoutRef, ElementType } from "react"; import { Equal, Expect } from "../helpers/type-utils"; -export const Wrapper = >( +export const Wrapper = ( props: { as: T; } & ComponentPropsWithoutRef, diff --git a/src/08-advanced-patterns/72-as-prop-with-default.problem.tsx b/src/08-advanced-patterns/72-as-prop-with-default.problem.tsx index e016fee..3030150 100644 --- a/src/08-advanced-patterns/72-as-prop-with-default.problem.tsx +++ b/src/08-advanced-patterns/72-as-prop-with-default.problem.tsx @@ -1,7 +1,7 @@ import { ComponentPropsWithoutRef, ElementType } from "react"; import { Equal, Expect } from "../helpers/type-utils"; -export const Link = >( +export const Link = ( props: { as: T; } & ComponentPropsWithoutRef, diff --git a/src/08-advanced-patterns/72-as-prop-with-default.solution.tsx b/src/08-advanced-patterns/72-as-prop-with-default.solution.tsx index a2fbc60..d6328e1 100644 --- a/src/08-advanced-patterns/72-as-prop-with-default.solution.tsx +++ b/src/08-advanced-patterns/72-as-prop-with-default.solution.tsx @@ -1,7 +1,7 @@ import { ComponentPropsWithoutRef, ElementType } from "react"; import { Equal, Expect } from "../helpers/type-utils"; -export const Link = = "a">( +export const Link = ( props: { as?: T; } & ComponentPropsWithoutRef, diff --git a/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.problem.tsx b/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.problem.tsx index fd330b7..22c7d80 100644 --- a/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.problem.tsx +++ b/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.problem.tsx @@ -2,7 +2,7 @@ import { ComponentPropsWithoutRef, ElementType, forwardRef } from "react"; import { Equal, Expect } from "../helpers/type-utils"; export const Link = forwardRef( - = "a">( + ( props: { as?: T; } & ComponentPropsWithoutRef, From 490ca0b34138a7ffcc173ed5232d6629631089ea Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 24 Jul 2023 11:52:56 +0100 Subject: [PATCH 025/105] Possible forwardRef solution --- .../72-as-prop-with-default.problem.tsx | 3 +- ...=> 72-as-prop-with-default.solution.1.tsx} | 3 + .../72-as-prop-with-default.solution.2.tsx | 46 +++++++++++++ .../72.5-as-prop-with-forward-ref.problem.tsx | 36 +++++----- ...72.5-as-prop-with-forward-ref.solution.tsx | 68 ++++++++++++------- 5 files changed, 114 insertions(+), 42 deletions(-) rename src/08-advanced-patterns/{72-as-prop-with-default.solution.tsx => 72-as-prop-with-default.solution.1.tsx} (91%) create mode 100644 src/08-advanced-patterns/72-as-prop-with-default.solution.2.tsx diff --git a/src/08-advanced-patterns/72-as-prop-with-default.problem.tsx b/src/08-advanced-patterns/72-as-prop-with-default.problem.tsx index 3030150..bd440f6 100644 --- a/src/08-advanced-patterns/72-as-prop-with-default.problem.tsx +++ b/src/08-advanced-patterns/72-as-prop-with-default.problem.tsx @@ -10,7 +10,7 @@ export const Link = ( return ; }; -// Should be a 'a' tag by default! +// 1. Should be a 'a' tag by default! ; const Custom = (props: { thisIsRequired: boolean }) => { @@ -22,6 +22,7 @@ const Custom = (props: { thisIsRequired: boolean }) => { // @ts-expect-error Property 'thisIsRequired' is missing ; +// 2. Should still give you autocomplete options! { diff --git a/src/08-advanced-patterns/72-as-prop-with-default.solution.tsx b/src/08-advanced-patterns/72-as-prop-with-default.solution.1.tsx similarity index 91% rename from src/08-advanced-patterns/72-as-prop-with-default.solution.tsx rename to src/08-advanced-patterns/72-as-prop-with-default.solution.1.tsx index d6328e1..ea8f9e6 100644 --- a/src/08-advanced-patterns/72-as-prop-with-default.solution.tsx +++ b/src/08-advanced-patterns/72-as-prop-with-default.solution.1.tsx @@ -1,6 +1,9 @@ import { ComponentPropsWithoutRef, ElementType } from "react"; import { Equal, Expect } from "../helpers/type-utils"; +/** + * This NEARLY works, but removes autocomplete for the 'as' prop. + */ export const Link = ( props: { as?: T; diff --git a/src/08-advanced-patterns/72-as-prop-with-default.solution.2.tsx b/src/08-advanced-patterns/72-as-prop-with-default.solution.2.tsx new file mode 100644 index 0000000..2e0fc12 --- /dev/null +++ b/src/08-advanced-patterns/72-as-prop-with-default.solution.2.tsx @@ -0,0 +1,46 @@ +import { ComponentPropsWithoutRef, ElementType } from "react"; +import { Equal, Expect } from "../helpers/type-utils"; + +/** + * Function overloads are another solution which work. We're getting + * closer to extreme verbosity, but it works! + * + * Though - the error at the bottom of the file becomes much + * harder to read. + */ + +function Link( + props: { + as: T; + } & ComponentPropsWithoutRef, +): React.ReactNode; +function Link(props: ComponentPropsWithoutRef<"a">): React.ReactNode; +function Link( + props: { + as?: T; + } & ComponentPropsWithoutRef, +) { + const { as: Comp = "a", ...rest } = props; + return ; +} + +; + +const Custom = (props: { thisIsRequired: boolean }) => { + return null; +}; + +; + +// @ts-expect-error Property 'thisIsRequired' is missing +; + + { + type test = Expect>>; + }} +>; + +// @ts-expect-error: Property 'href' does not exist +; diff --git a/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.problem.tsx b/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.problem.tsx index 22c7d80..ddb8f33 100644 --- a/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.problem.tsx +++ b/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.problem.tsx @@ -1,16 +1,23 @@ -import { ComponentPropsWithoutRef, ElementType, forwardRef } from "react"; +import { + ComponentPropsWithoutRef, + ElementType, + JSXElementConstructor, + forwardRef, +} from "react"; import { Equal, Expect } from "../helpers/type-utils"; -export const Link = forwardRef( - ( - props: { - as?: T; - } & ComponentPropsWithoutRef, - ) => { - const { as: Comp = "a", ...rest } = props; - return ; - }, -); +function UnwrappedLink< + T extends keyof JSX.IntrinsicElements | JSXElementConstructor, +>( + props: { + as?: T; + } & ComponentPropsWithoutRef, +) { + const { as: Comp = "a", ...rest } = props; + return ; +} + +const Link = forwardRef(UnwrappedLink); ; @@ -30,8 +37,5 @@ const Custom = (props: { thisIsRequired: boolean }) => { }} >; -; +// @ts-expect-error: Property 'href' does not exist +; diff --git a/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.solution.tsx b/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.solution.tsx index 33cd7e9..2e9f2c0 100644 --- a/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.solution.tsx +++ b/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.solution.tsx @@ -1,7 +1,9 @@ import { ComponentProps, + ComponentPropsWithRef, ComponentPropsWithoutRef, ElementType, + JSXElementConstructor, forwardRef, useRef, } from "react"; @@ -13,23 +15,28 @@ type FixedForwardRef = ( const fixedForwardRef = forwardRef as FixedForwardRef; -export const Link = fixedForwardRef( - ( - props: { - as?: T; - } & ComponentProps, - ) => { - const { as = "a", ...rest } = props; - const Comp = as as any; - return ; - }, -); - -const Test = () => { - const ref = useRef(null); - - return ; -}; +type Constraint = keyof JSX.IntrinsicElements | JSXElementConstructor; + +type Props< + T extends Constraint, + P = ComponentProps, +> = P; + +type Example = Props<"button">; + +function UnwrappedLink(props: { as?: T } & Props) { + const { as: Comp = "a", ...rest } = props; + return ; +} + +const Link = fixedForwardRef(UnwrappedLink); + + { + type test = Expect>>; + }} +>; const Custom = (props: { thisIsRequired: boolean }) => { return null; @@ -40,18 +47,29 @@ const Custom = (props: { thisIsRequired: boolean }) => { // @ts-expect-error Property 'thisIsRequired' is missing ; -const ref = useRef(null); - { type test = Expect>>; }} - ref={ref} >; -; +const ref = useRef(null); +const wrongRef = useRef(null); + +Link({ + ref, +}); + +Link({ + as: Custom, + thisIsRequired: true, +}); + +Link({ + // @ts-expect-error + ref: wrongRef, +}); + +// @ts-expect-error: Property 'href' does not exist +; From 9a8df08f2bf6500a12a74fa65a1c284b68cd07c2 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 24 Jul 2023 12:46:44 +0100 Subject: [PATCH 026/105] WIP --- .../72.5-as-prop-with-forward-ref.problem.tsx | 1 - ...72.5-as-prop-with-forward-ref.solution.tsx | 48 ++++++++++--------- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.problem.tsx b/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.problem.tsx index ddb8f33..d82101a 100644 --- a/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.problem.tsx +++ b/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.problem.tsx @@ -1,6 +1,5 @@ import { ComponentPropsWithoutRef, - ElementType, JSXElementConstructor, forwardRef, } from "react"; diff --git a/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.solution.tsx b/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.solution.tsx index 2e9f2c0..33c0a46 100644 --- a/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.solution.tsx +++ b/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.solution.tsx @@ -1,12 +1,4 @@ -import { - ComponentProps, - ComponentPropsWithRef, - ComponentPropsWithoutRef, - ElementType, - JSXElementConstructor, - forwardRef, - useRef, -} from "react"; +import { ComponentPropsWithRef, ElementType, forwardRef, useRef } from "react"; import { Equal, Expect } from "../helpers/type-utils"; type FixedForwardRef = ( @@ -15,16 +7,11 @@ type FixedForwardRef = ( const fixedForwardRef = forwardRef as FixedForwardRef; -type Constraint = keyof JSX.IntrinsicElements | JSXElementConstructor; - -type Props< - T extends Constraint, - P = ComponentProps, -> = P; - -type Example = Props<"button">; - -function UnwrappedLink(props: { as?: T } & Props) { +function UnwrappedLink( + props: { + as?: T; + } & Omit, "as">, +) { const { as: Comp = "a", ...rest } = props; return ; } @@ -38,9 +25,14 @@ const Link = fixedForwardRef(UnwrappedLink); }} >; -const Custom = (props: { thisIsRequired: boolean }) => { - return null; -}; +const Custom = forwardRef( + ( + props: { thisIsRequired: boolean }, + ref: React.ForwardedRef, + ) => { + return
; + }, +); ; @@ -61,15 +53,27 @@ Link({ ref, }); +Link({ + // @ts-expect-error + ref: wrongRef, +}); + Link({ as: Custom, thisIsRequired: true, + ref: ref, }); Link({ + as: Custom, + thisIsRequired: true, // @ts-expect-error ref: wrongRef, }); // @ts-expect-error: Property 'href' does not exist ; + +Link({ + as: "div", +}); From 8c4fe9767be6e39c37b00901356146aed2871ee7 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 24 Jul 2023 14:18:24 +0100 Subject: [PATCH 027/105] Got it working! --- .../72.5-as-prop-with-forward-ref.solution.tsx | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.solution.tsx b/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.solution.tsx index 33c0a46..10d646b 100644 --- a/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.solution.tsx +++ b/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.solution.tsx @@ -1,4 +1,4 @@ -import { ComponentPropsWithRef, ElementType, forwardRef, useRef } from "react"; +import { ComponentProps, ElementType, forwardRef, useRef } from "react"; import { Equal, Expect } from "../helpers/type-utils"; type FixedForwardRef = ( @@ -7,10 +7,20 @@ type FixedForwardRef = ( const fixedForwardRef = forwardRef as FixedForwardRef; -function UnwrappedLink( +type DistributiveOmit = T extends any + ? Omit + : never; + +function UnwrappedLink< + T extends ElementType, + Props extends DistributiveOmit< + ComponentProps, + "as" + >, +>( props: { as?: T; - } & Omit, "as">, + } & Props, ) { const { as: Comp = "a", ...rest } = props; return ; From dbafb32ac7500b7a9cb6500dd4e0eef3e6048440 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 24 Jul 2023 14:41:07 +0100 Subject: [PATCH 028/105] Finished 'as' work --- .../70-as-prop.problem.tsx | 62 +++++-- .../70-as-prop.solution.1.tsx | 58 ++++++- .../70-as-prop.solution.2.tsx | 58 ++++++- ...as-prop-with-custom-components.problem.tsx | 54 +++++- ...s-prop-with-custom-components.solution.tsx | 59 ++++++- .../72-as-prop-with-default.problem.tsx | 89 ++++++++-- .../72-as-prop-with-default.solution.1.tsx | 87 ++++++++-- .../72-as-prop-with-default.solution.2.tsx | 107 ++++++++---- .../72.5-as-prop-with-forward-ref.problem.tsx | 122 +++++++++++-- ...72.5-as-prop-with-forward-ref.solution.tsx | 162 ++++++++++++------ 10 files changed, 681 insertions(+), 177 deletions(-) diff --git a/src/08-advanced-patterns/70-as-prop.problem.tsx b/src/08-advanced-patterns/70-as-prop.problem.tsx index 8148328..e75a490 100644 --- a/src/08-advanced-patterns/70-as-prop.problem.tsx +++ b/src/08-advanced-patterns/70-as-prop.problem.tsx @@ -22,19 +22,59 @@ * - Indexed access types */ +import { Equal, Expect } from "../helpers/type-utils"; + export const Wrapper = (props: any) => { const Comp = props.as; return ; }; -// Should work, and you should get autocomplete on the -// props for the 'a' tag -const example1 = ; - -const example2 = ( - -); +/** + * Should work specifying a 'button' + */ + +const Example1 = () => { + return ( + <> + + + { + type test = Expect< + Equal> + >; + }} + > + + ); +}; + +/** + * Should work specifying a 'div' + */ + +const Example2 = () => { + return ( + <> + + + { + type test = Expect>>; + }} + > + + ); +}; diff --git a/src/08-advanced-patterns/70-as-prop.solution.1.tsx b/src/08-advanced-patterns/70-as-prop.solution.1.tsx index 33facb6..939c576 100644 --- a/src/08-advanced-patterns/70-as-prop.solution.1.tsx +++ b/src/08-advanced-patterns/70-as-prop.solution.1.tsx @@ -1,3 +1,5 @@ +import { Equal, Expect } from "../helpers/type-utils"; + type AsProps = { [K in keyof JSX.IntrinsicElements]: { as: K; @@ -9,12 +11,52 @@ export const Wrapper = (props: AsProps) => { return ; }; -const example1 = ; +/** + * Should work specifying a 'button' + */ + +const Example1 = () => { + return ( + <> + + + { + type test = Expect< + Equal> + >; + }} + > + + ); +}; -const example2 = ( - -); +/** + * Should work specifying a 'div' + */ + +const Example2 = () => { + return ( + <> + + + { + type test = Expect>>; + }} + > + + ); +}; diff --git a/src/08-advanced-patterns/70-as-prop.solution.2.tsx b/src/08-advanced-patterns/70-as-prop.solution.2.tsx index 35b4b9a..d2729ad 100644 --- a/src/08-advanced-patterns/70-as-prop.solution.2.tsx +++ b/src/08-advanced-patterns/70-as-prop.solution.2.tsx @@ -1,3 +1,5 @@ +import { Equal, Expect } from "../helpers/type-utils"; + export const Wrapper = ( props: { as: TAs; @@ -8,12 +10,52 @@ export const Wrapper = ( return ; }; -const example1 = ; +/** + * Should work specifying a 'button' + */ + +const Example1 = () => { + return ( + <> + + + { + type test = Expect< + Equal> + >; + }} + > + + ); +}; -const example2 = ( - -); +/** + * Should work specifying a 'div' + */ + +const Example2 = () => { + return ( + <> + + + { + type test = Expect>>; + }} + > + + ); +}; diff --git a/src/08-advanced-patterns/71-as-prop-with-custom-components.problem.tsx b/src/08-advanced-patterns/71-as-prop-with-custom-components.problem.tsx index 19c5bf2..dc2c983 100644 --- a/src/08-advanced-patterns/71-as-prop-with-custom-components.problem.tsx +++ b/src/08-advanced-patterns/71-as-prop-with-custom-components.problem.tsx @@ -1,4 +1,5 @@ import React from "react"; +import { Equal, Expect } from "../helpers/type-utils"; /** * This is a further extension of 'as'. This time, we can pass in @@ -14,8 +15,55 @@ export const Wrapper = (props: { as: unknown }) => { return ; }; -const Link = (props: { href: string; children?: React.ReactNode }) => { - return {props.children}; +/** + * Should work specifying a 'button' + */ + +const Example1 = () => { + return ( + <> + + + { + type test = Expect< + Equal> + >; + }} + > + + ); }; -; +/** + * Should work with Custom components! + */ + +const Custom = ( + props: { thisIsRequired: boolean }, + ref: React.ForwardedRef, +) => { + return ; +}; + +const Example2 = () => { + return ( + <> + + + + {/* @ts-expect-error thisIsRequired is not being passed */} + + + ); +}; diff --git a/src/08-advanced-patterns/71-as-prop-with-custom-components.solution.tsx b/src/08-advanced-patterns/71-as-prop-with-custom-components.solution.tsx index fe09d73..be6635a 100644 --- a/src/08-advanced-patterns/71-as-prop-with-custom-components.solution.tsx +++ b/src/08-advanced-patterns/71-as-prop-with-custom-components.solution.tsx @@ -10,14 +10,55 @@ export const Wrapper = ( return ; }; -const Link = (props: { href: string; children?: React.ReactNode }) => { - return {props.children}; +/** + * Should work specifying a 'button' + */ + +const Example1 = () => { + return ( + <> + + + { + type test = Expect< + Equal> + >; + }} + > + + ); +}; + +/** + * Should work with Custom components! + */ + +const Custom = ( + props: { thisIsRequired: boolean }, + ref: React.ForwardedRef, +) => { + return ; }; -; - { - type test = Expect>>; - }} -/>; +const Example2 = () => { + return ( + <> + + + + {/* @ts-expect-error thisIsRequired is not being passed */} + + + ); +}; diff --git a/src/08-advanced-patterns/72-as-prop-with-default.problem.tsx b/src/08-advanced-patterns/72-as-prop-with-default.problem.tsx index bd440f6..afd36e3 100644 --- a/src/08-advanced-patterns/72-as-prop-with-default.problem.tsx +++ b/src/08-advanced-patterns/72-as-prop-with-default.problem.tsx @@ -10,28 +10,79 @@ export const Link = ( return ; }; -// 1. Should be a 'a' tag by default! -; +/** + * Should work without specifying 'as' + */ -const Custom = (props: { thisIsRequired: boolean }) => { - return null; +const Example1 = () => { + return ( + <> + + + { + type test = Expect< + Equal> + >; + }} + > + + ); +}; + +/** + * Should work specifying a 'button' + */ + +const Example2 = () => { + return ( + <> + + + { + type test = Expect< + Equal> + >; + }} + > + + ); }; -; +/** + * Should work with Custom components! + */ -// @ts-expect-error Property 'thisIsRequired' is missing -; +const Custom = ( + props: { thisIsRequired: boolean }, + ref: React.ForwardedRef, +) => { + return ; +}; -// 2. Should still give you autocomplete options! - { - type test = Expect>>; - }} ->; +const Example3 = () => { + return ( + <> + + -; + {/* @ts-expect-error thisIsRequired is not being passed */} + + + ); +}; diff --git a/src/08-advanced-patterns/72-as-prop-with-default.solution.1.tsx b/src/08-advanced-patterns/72-as-prop-with-default.solution.1.tsx index ea8f9e6..67e196a 100644 --- a/src/08-advanced-patterns/72-as-prop-with-default.solution.1.tsx +++ b/src/08-advanced-patterns/72-as-prop-with-default.solution.1.tsx @@ -13,26 +13,79 @@ export const Link = ( return ; }; -; +/** + * Should work without specifying 'as' + */ + +const Example1 = () => { + return ( + <> + + + { + type test = Expect< + Equal> + >; + }} + > + + ); +}; + +/** + * Should work specifying a 'button' + */ + +const Example2 = () => { + return ( + <> + -const Custom = (props: { thisIsRequired: boolean }) => { - return null; + { + type test = Expect< + Equal> + >; + }} + > + + ); }; -; +/** + * Should work with Custom components! + */ -// @ts-expect-error Property 'thisIsRequired' is missing -; +const Custom = ( + props: { thisIsRequired: boolean }, + ref: React.ForwardedRef, +) => { + return ; +}; - { - type test = Expect>>; - }} ->; +const Example3 = () => { + return ( + <> + + -; + {/* @ts-expect-error thisIsRequired is not being passed */} + + + ); +}; diff --git a/src/08-advanced-patterns/72-as-prop-with-default.solution.2.tsx b/src/08-advanced-patterns/72-as-prop-with-default.solution.2.tsx index 2e0fc12..0706e64 100644 --- a/src/08-advanced-patterns/72-as-prop-with-default.solution.2.tsx +++ b/src/08-advanced-patterns/72-as-prop-with-default.solution.2.tsx @@ -1,46 +1,91 @@ -import { ComponentPropsWithoutRef, ElementType } from "react"; +import { ComponentPropsWithoutRef, ElementType, useRef } from "react"; import { Equal, Expect } from "../helpers/type-utils"; /** - * Function overloads are another solution which work. We're getting - * closer to extreme verbosity, but it works! - * - * Though - the error at the bottom of the file becomes much - * harder to read. + * This NEARLY works, but removes autocomplete for the 'as' prop. */ - -function Link( - props: { - as: T; - } & ComponentPropsWithoutRef, -): React.ReactNode; -function Link(props: ComponentPropsWithoutRef<"a">): React.ReactNode; -function Link( +export const Link = ( props: { as?: T; - } & ComponentPropsWithoutRef, -) { + } & ComponentPropsWithoutRef, +) => { const { as: Comp = "a", ...rest } = props; return ; -} +}; + +/** + * Should work without specifying 'as' + */ + +const Example1 = () => { + return ( + <> + + + { + type test = Expect< + Equal> + >; + }} + > + + ); +}; + +/** + * Should work specifying a 'button' + */ -; +const Example2 = () => { + return ( + <> + -const Custom = (props: { thisIsRequired: boolean }) => { - return null; + { + type test = Expect< + Equal> + >; + }} + > + + ); }; -; +/** + * Should work with Custom components! + */ -// @ts-expect-error Property 'thisIsRequired' is missing -; +const Custom = ( + props: { thisIsRequired: boolean }, + ref: React.ForwardedRef, +) => { + return ; +}; - { - type test = Expect>>; - }} ->; +const Example3 = () => { + return ( + <> + + -// @ts-expect-error: Property 'href' does not exist -; + {/* @ts-expect-error thisIsRequired is not being passed */} + + + ); +}; diff --git a/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.problem.tsx b/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.problem.tsx index d82101a..84a08d5 100644 --- a/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.problem.tsx +++ b/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.problem.tsx @@ -2,6 +2,7 @@ import { ComponentPropsWithoutRef, JSXElementConstructor, forwardRef, + useRef, } from "react"; import { Equal, Expect } from "../helpers/type-utils"; @@ -18,23 +19,116 @@ function UnwrappedLink< const Link = forwardRef(UnwrappedLink); -; +/** + * Should work without specifying 'as' + */ -const Custom = (props: { thisIsRequired: boolean }) => { - return null; +const Example1 = () => { + const ref = useRef(null); + const wrongRef = useRef(null); + + return ( + <> + + + + + + + { + type test = Expect< + Equal> + >; + }} + > + + ); }; -; +/** + * Should work specifying a 'button' + */ -// @ts-expect-error Property 'thisIsRequired' is missing -; +const Example2 = () => { + const ref = useRef(null); + const wrongRef = useRef(null); - { - type test = Expect>>; - }} ->; + return ( + <> + {/* CHECK ME! Check if autocomplete works on 'as' */} + -// @ts-expect-error: Property 'href' does not exist -; + + + + + + + { + type test = Expect< + Equal> + >; + }} + > + + ); +}; + +/** + * Should work with Custom components! + */ + +const Custom = forwardRef( + ( + props: { thisIsRequired: boolean }, + ref: React.ForwardedRef, + ) => { + return ; + }, +); + +const Example3 = () => { + const ref = useRef(null); + const wrongRef = useRef(null); + return ( + <> + + + + {/* @ts-expect-error thisIsRequired is not being passed */} + + + + + + + ); +}; diff --git a/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.solution.tsx b/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.solution.tsx index 10d646b..04299c6 100644 --- a/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.solution.tsx +++ b/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.solution.tsx @@ -11,16 +11,10 @@ type DistributiveOmit = T extends any ? Omit : never; -function UnwrappedLink< - T extends ElementType, - Props extends DistributiveOmit< - ComponentProps, - "as" - >, ->( +function UnwrappedLink( props: { as?: T; - } & Props, + } & DistributiveOmit, "as">, ) { const { as: Comp = "a", ...rest } = props; return ; @@ -28,12 +22,83 @@ function UnwrappedLink< const Link = fixedForwardRef(UnwrappedLink); - { - type test = Expect>>; - }} ->; +/** + * Should work without specifying 'as' + */ + +const Example1 = () => { + const ref = useRef(null); + const wrongRef = useRef(null); + + return ( + <> + + + + + + + { + type test = Expect< + Equal> + >; + }} + > + + ); +}; + +/** + * Should work specifying a 'button' + */ + +const Example2 = () => { + const ref = useRef(null); + const wrongRef = useRef(null); + + return ( + <> + {/* CHECK ME! Check if autocomplete works on 'as' */} + + + + + + + + + { + type test = Expect< + Equal> + >; + }} + > + + ); +}; + +/** + * Should work with Custom components! + */ const Custom = forwardRef( ( @@ -44,46 +109,29 @@ const Custom = forwardRef( }, ); -; - -// @ts-expect-error Property 'thisIsRequired' is missing -; - - { - type test = Expect>>; - }} ->; - -const ref = useRef(null); -const wrongRef = useRef(null); - -Link({ - ref, -}); - -Link({ - // @ts-expect-error - ref: wrongRef, -}); - -Link({ - as: Custom, - thisIsRequired: true, - ref: ref, -}); - -Link({ - as: Custom, - thisIsRequired: true, - // @ts-expect-error - ref: wrongRef, -}); - -// @ts-expect-error: Property 'href' does not exist -; - -Link({ - as: "div", -}); +const Example3 = () => { + const ref = useRef(null); + const wrongRef = useRef(null); + return ( + <> + + + + {/* @ts-expect-error thisIsRequired is not being passed */} + + + + + + + ); +}; From d680265035f50538beff7f814069b98a94cfe3b5 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 24 Jul 2023 14:45:35 +0100 Subject: [PATCH 029/105] Various fixes --- .../72-as-prop-with-default.problem.tsx | 4 ++-- .../72-as-prop-with-default.solution.2.tsx | 3 --- ...m.tsx => 73-as-prop-with-forward-ref.problem.tsx} | 12 +++++------- ....tsx => 73-as-prop-with-forward-ref.solution.tsx} | 4 ++++ ...xplainer.tsx => 74-react-hook-form.explainer.tsx} | 0 ...em.tsx => 75-react-hook-form-wrapper.problem.tsx} | 0 ...n.tsx => 75-react-hook-form-wrapper.solution.tsx} | 0 ...elect.problem.tsx => 76-react-select.problem.tsx} | 0 ...ect.solution.tsx => 76-react-select.solution.tsx} | 0 ...uery.explainer.ts => 77-react-query.explainer.ts} | 0 ....problem.ts => 78-react-query-wrapper.problem.ts} | 0 ...olution.ts => 78-react-query-wrapper.solution.ts} | 0 12 files changed, 11 insertions(+), 12 deletions(-) rename src/08-advanced-patterns/{72.5-as-prop-with-forward-ref.problem.tsx => 73-as-prop-with-forward-ref.problem.tsx} (93%) rename src/08-advanced-patterns/{72.5-as-prop-with-forward-ref.solution.tsx => 73-as-prop-with-forward-ref.solution.tsx} (97%) rename src/09-external-libraries/{73-react-hook-form.explainer.tsx => 74-react-hook-form.explainer.tsx} (100%) rename src/09-external-libraries/{74-react-hook-form-wrapper.problem.tsx => 75-react-hook-form-wrapper.problem.tsx} (100%) rename src/09-external-libraries/{74-react-hook-form-wrapper.solution.tsx => 75-react-hook-form-wrapper.solution.tsx} (100%) rename src/09-external-libraries/{75-react-select.problem.tsx => 76-react-select.problem.tsx} (100%) rename src/09-external-libraries/{75-react-select.solution.tsx => 76-react-select.solution.tsx} (100%) rename src/09-external-libraries/{76-react-query.explainer.ts => 77-react-query.explainer.ts} (100%) rename src/09-external-libraries/{77-react-query-wrapper.problem.ts => 78-react-query-wrapper.problem.ts} (100%) rename src/09-external-libraries/{77-react-query-wrapper.solution.ts => 78-react-query-wrapper.solution.ts} (100%) diff --git a/src/08-advanced-patterns/72-as-prop-with-default.problem.tsx b/src/08-advanced-patterns/72-as-prop-with-default.problem.tsx index afd36e3..9be70e8 100644 --- a/src/08-advanced-patterns/72-as-prop-with-default.problem.tsx +++ b/src/08-advanced-patterns/72-as-prop-with-default.problem.tsx @@ -6,8 +6,8 @@ export const Link = ( as: T; } & ComponentPropsWithoutRef, ) => { - const { as: Comp, ...rest } = props; - return ; + const Comp = props.as; + return ; }; /** diff --git a/src/08-advanced-patterns/72-as-prop-with-default.solution.2.tsx b/src/08-advanced-patterns/72-as-prop-with-default.solution.2.tsx index 0706e64..85d3dac 100644 --- a/src/08-advanced-patterns/72-as-prop-with-default.solution.2.tsx +++ b/src/08-advanced-patterns/72-as-prop-with-default.solution.2.tsx @@ -1,9 +1,6 @@ import { ComponentPropsWithoutRef, ElementType, useRef } from "react"; import { Equal, Expect } from "../helpers/type-utils"; -/** - * This NEARLY works, but removes autocomplete for the 'as' prop. - */ export const Link = ( props: { as?: T; diff --git a/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.problem.tsx b/src/08-advanced-patterns/73-as-prop-with-forward-ref.problem.tsx similarity index 93% rename from src/08-advanced-patterns/72.5-as-prop-with-forward-ref.problem.tsx rename to src/08-advanced-patterns/73-as-prop-with-forward-ref.problem.tsx index 84a08d5..06d4c07 100644 --- a/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.problem.tsx +++ b/src/08-advanced-patterns/73-as-prop-with-forward-ref.problem.tsx @@ -1,21 +1,19 @@ import { ComponentPropsWithoutRef, - JSXElementConstructor, + ElementType, forwardRef, useRef, } from "react"; import { Equal, Expect } from "../helpers/type-utils"; -function UnwrappedLink< - T extends keyof JSX.IntrinsicElements | JSXElementConstructor, ->( +export const UnwrappedLink = ( props: { as?: T; - } & ComponentPropsWithoutRef, -) { + } & ComponentPropsWithoutRef, +) => { const { as: Comp = "a", ...rest } = props; return ; -} +}; const Link = forwardRef(UnwrappedLink); diff --git a/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.solution.tsx b/src/08-advanced-patterns/73-as-prop-with-forward-ref.solution.tsx similarity index 97% rename from src/08-advanced-patterns/72.5-as-prop-with-forward-ref.solution.tsx rename to src/08-advanced-patterns/73-as-prop-with-forward-ref.solution.tsx index 04299c6..9b5d9f2 100644 --- a/src/08-advanced-patterns/72.5-as-prop-with-forward-ref.solution.tsx +++ b/src/08-advanced-patterns/73-as-prop-with-forward-ref.solution.tsx @@ -1,12 +1,16 @@ import { ComponentProps, ElementType, forwardRef, useRef } from "react"; import { Equal, Expect } from "../helpers/type-utils"; +// Added fixedForwardRef from a previous exercise + type FixedForwardRef = ( render: (props: P, ref: React.Ref) => React.ReactNode, ) => (props: P & React.RefAttributes) => React.ReactNode; const fixedForwardRef = forwardRef as FixedForwardRef; +// Added a DistributiveOmit type + type DistributiveOmit = T extends any ? Omit : never; diff --git a/src/09-external-libraries/73-react-hook-form.explainer.tsx b/src/09-external-libraries/74-react-hook-form.explainer.tsx similarity index 100% rename from src/09-external-libraries/73-react-hook-form.explainer.tsx rename to src/09-external-libraries/74-react-hook-form.explainer.tsx diff --git a/src/09-external-libraries/74-react-hook-form-wrapper.problem.tsx b/src/09-external-libraries/75-react-hook-form-wrapper.problem.tsx similarity index 100% rename from src/09-external-libraries/74-react-hook-form-wrapper.problem.tsx rename to src/09-external-libraries/75-react-hook-form-wrapper.problem.tsx diff --git a/src/09-external-libraries/74-react-hook-form-wrapper.solution.tsx b/src/09-external-libraries/75-react-hook-form-wrapper.solution.tsx similarity index 100% rename from src/09-external-libraries/74-react-hook-form-wrapper.solution.tsx rename to src/09-external-libraries/75-react-hook-form-wrapper.solution.tsx diff --git a/src/09-external-libraries/75-react-select.problem.tsx b/src/09-external-libraries/76-react-select.problem.tsx similarity index 100% rename from src/09-external-libraries/75-react-select.problem.tsx rename to src/09-external-libraries/76-react-select.problem.tsx diff --git a/src/09-external-libraries/75-react-select.solution.tsx b/src/09-external-libraries/76-react-select.solution.tsx similarity index 100% rename from src/09-external-libraries/75-react-select.solution.tsx rename to src/09-external-libraries/76-react-select.solution.tsx diff --git a/src/09-external-libraries/76-react-query.explainer.ts b/src/09-external-libraries/77-react-query.explainer.ts similarity index 100% rename from src/09-external-libraries/76-react-query.explainer.ts rename to src/09-external-libraries/77-react-query.explainer.ts diff --git a/src/09-external-libraries/77-react-query-wrapper.problem.ts b/src/09-external-libraries/78-react-query-wrapper.problem.ts similarity index 100% rename from src/09-external-libraries/77-react-query-wrapper.problem.ts rename to src/09-external-libraries/78-react-query-wrapper.problem.ts diff --git a/src/09-external-libraries/77-react-query-wrapper.solution.ts b/src/09-external-libraries/78-react-query-wrapper.solution.ts similarity index 100% rename from src/09-external-libraries/77-react-query-wrapper.solution.ts rename to src/09-external-libraries/78-react-query-wrapper.solution.ts From 36ad22a3ea21a21ea8e5773df4206abbc6de92af Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 24 Jul 2023 15:01:21 +0100 Subject: [PATCH 030/105] Added comment to 73 --- src/08-advanced-patterns/68-hoc.solution.tsx | 2 +- .../73-as-prop-with-forward-ref.problem.tsx | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/08-advanced-patterns/68-hoc.solution.tsx b/src/08-advanced-patterns/68-hoc.solution.tsx index 6254800..2cb7942 100644 --- a/src/08-advanced-patterns/68-hoc.solution.tsx +++ b/src/08-advanced-patterns/68-hoc.solution.tsx @@ -1,7 +1,7 @@ import { Router, useRouter } from "fake-external-lib"; export const withRouter = ( - Component: React.ComponentType, + Component: React.FC, ) => { const NewComponent = (props: Omit) => { const router = useRouter(); diff --git a/src/08-advanced-patterns/73-as-prop-with-forward-ref.problem.tsx b/src/08-advanced-patterns/73-as-prop-with-forward-ref.problem.tsx index 06d4c07..bf28cd4 100644 --- a/src/08-advanced-patterns/73-as-prop-with-forward-ref.problem.tsx +++ b/src/08-advanced-patterns/73-as-prop-with-forward-ref.problem.tsx @@ -6,6 +6,13 @@ import { } from "react"; import { Equal, Expect } from "../helpers/type-utils"; +/** + * FYI - this solution took me the best part of a whole day to find, + * and the help of several TS experts in the community. + * + * So, don't feel bad if you don't find it at all. + */ + export const UnwrappedLink = ( props: { as?: T; From 5cc805de541db51b4d79760a014f22d9ec61afa4 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 24 Jul 2023 15:31:03 +0100 Subject: [PATCH 031/105] Tweak --- src/08-advanced-patterns/63-lazy-load-component.problem.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/08-advanced-patterns/63-lazy-load-component.problem.tsx b/src/08-advanced-patterns/63-lazy-load-component.problem.tsx index 9deb327..7fe3b5e 100644 --- a/src/08-advanced-patterns/63-lazy-load-component.problem.tsx +++ b/src/08-advanced-patterns/63-lazy-load-component.problem.tsx @@ -11,8 +11,10 @@ type Props = { * But it's not typed correctly, and it's not generic enough. * Fix the typing errors, and make it generic enough to support any component. * - * Hint - React.ComponentProps will come in handy - as will a helper called - * React.ComponentType. + * Hints: + * + * - You'll need to make this a generic component! + * - React.ComponentProps will come in handy, as will React.ComponentType */ function LazyLoad({ loader, ...props }: Props) { const LazyComponent = useMemo(() => lazy(loader), [loader]); From 3f4586b8b4bedf636fed60cabcc8ce4d4ab40370 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 24 Jul 2023 15:42:35 +0100 Subject: [PATCH 032/105] Changed 63 --- .../63-lazy-load-component.solution.tsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/08-advanced-patterns/63-lazy-load-component.solution.tsx b/src/08-advanced-patterns/63-lazy-load-component.solution.tsx index c36e4a2..fd52b96 100644 --- a/src/08-advanced-patterns/63-lazy-load-component.solution.tsx +++ b/src/08-advanced-patterns/63-lazy-load-component.solution.tsx @@ -1,10 +1,12 @@ -import { lazy, Suspense, useMemo } from "react"; +import { ComponentProps, ComponentType, lazy, Suspense, useMemo } from "react"; -type Props> = React.ComponentProps & { - loader: () => Promise<{ default: C }>; -}; +type Props> = { + loader: () => Promise<{ + default: C; + }>; +} & ComponentProps; -function LazyLoad>({ +function LazyLoad>({ loader, ...props }: Props) { From 10c28d6d82b5dafbc2cc8bdd19034571d25d1e49 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 24 Jul 2023 15:43:50 +0100 Subject: [PATCH 033/105] Removed const generics --- .../64-const-generics-in-generic-components.problem.tsx | 7 ------- ...ender-props.problem.tsx => 64-render-props.problem.tsx} | 0 ...der-props.solution.tsx => 64-render-props.solution.tsx} | 0 ....1.tsx => 65-forward-ref-with-generics.explainer.1.tsx} | 0 ....2.tsx => 65-forward-ref-with-generics.explainer.2.tsx} | 0 ...er.3.ts => 65-forward-ref-with-generics.explainer.3.ts} | 0 ...em.tsx => 66-forward-ref-as-local-function.problem.tsx} | 0 ...tsx => 66-forward-ref-as-local-function.solution.1.tsx} | 0 ...tsx => 66-forward-ref-as-local-function.solution.2.tsx} | 0 .../{68-hoc.problem.tsx => 67-hoc.problem.tsx} | 0 .../{68-hoc.solution.tsx => 67-hoc.solution.tsx} | 0 ...=> 68-record-of-components-with-same-props.problem.tsx} | 0 ...68-record-of-components-with-same-props.solution.1.tsx} | 0 ...68-record-of-components-with-same-props.solution.2.tsx} | 0 .../{70-as-prop.problem.tsx => 69-as-prop.problem.tsx} | 0 ...70-as-prop.solution.1.tsx => 69-as-prop.solution.1.tsx} | 0 ...70-as-prop.solution.2.tsx => 69-as-prop.solution.2.tsx} | 0 ...m.tsx => 70-as-prop-with-custom-components.problem.tsx} | 0 ....tsx => 70-as-prop-with-custom-components.solution.tsx} | 0 ...ult.problem.tsx => 71-as-prop-with-default.problem.tsx} | 0 ...lution.1.tsx => 71-as-prop-with-default.solution.1.tsx} | 0 ...lution.2.tsx => 71-as-prop-with-default.solution.2.tsx} | 0 ...problem.tsx => 72-as-prop-with-forward-ref.problem.tsx} | 0 ...lution.tsx => 72-as-prop-with-forward-ref.solution.tsx} | 0 ...form.explainer.tsx => 73-react-hook-form.explainer.tsx} | 0 ....problem.tsx => 74-react-hook-form-wrapper.problem.tsx} | 0 ...olution.tsx => 74-react-hook-form-wrapper.solution.tsx} | 0 ...eact-select.problem.tsx => 75-react-select.problem.tsx} | 0 ...ct-select.solution.tsx => 75-react-select.solution.tsx} | 0 ...eact-query.explainer.ts => 76-react-query.explainer.ts} | 0 ...rapper.problem.ts => 77-react-query-wrapper.problem.ts} | 0 ...pper.solution.ts => 77-react-query-wrapper.solution.ts} | 0 32 files changed, 7 deletions(-) delete mode 100644 src/08-advanced-patterns/64-const-generics-in-generic-components.problem.tsx rename src/08-advanced-patterns/{65-render-props.problem.tsx => 64-render-props.problem.tsx} (100%) rename src/08-advanced-patterns/{65-render-props.solution.tsx => 64-render-props.solution.tsx} (100%) rename src/08-advanced-patterns/{66-forward-ref-with-generics.explainer.1.tsx => 65-forward-ref-with-generics.explainer.1.tsx} (100%) rename src/08-advanced-patterns/{66-forward-ref-with-generics.explainer.2.tsx => 65-forward-ref-with-generics.explainer.2.tsx} (100%) rename src/08-advanced-patterns/{66-forward-ref-with-generics.explainer.3.ts => 65-forward-ref-with-generics.explainer.3.ts} (100%) rename src/08-advanced-patterns/{67-forward-ref-as-local-function.problem.tsx => 66-forward-ref-as-local-function.problem.tsx} (100%) rename src/08-advanced-patterns/{67-forward-ref-as-local-function.solution.1.tsx => 66-forward-ref-as-local-function.solution.1.tsx} (100%) rename src/08-advanced-patterns/{67-forward-ref-as-local-function.solution.2.tsx => 66-forward-ref-as-local-function.solution.2.tsx} (100%) rename src/08-advanced-patterns/{68-hoc.problem.tsx => 67-hoc.problem.tsx} (100%) rename src/08-advanced-patterns/{68-hoc.solution.tsx => 67-hoc.solution.tsx} (100%) rename src/08-advanced-patterns/{69-record-of-components-with-same-props.problem.tsx => 68-record-of-components-with-same-props.problem.tsx} (100%) rename src/08-advanced-patterns/{69-record-of-components-with-same-props.solution.1.tsx => 68-record-of-components-with-same-props.solution.1.tsx} (100%) rename src/08-advanced-patterns/{69-record-of-components-with-same-props.solution.2.tsx => 68-record-of-components-with-same-props.solution.2.tsx} (100%) rename src/08-advanced-patterns/{70-as-prop.problem.tsx => 69-as-prop.problem.tsx} (100%) rename src/08-advanced-patterns/{70-as-prop.solution.1.tsx => 69-as-prop.solution.1.tsx} (100%) rename src/08-advanced-patterns/{70-as-prop.solution.2.tsx => 69-as-prop.solution.2.tsx} (100%) rename src/08-advanced-patterns/{71-as-prop-with-custom-components.problem.tsx => 70-as-prop-with-custom-components.problem.tsx} (100%) rename src/08-advanced-patterns/{71-as-prop-with-custom-components.solution.tsx => 70-as-prop-with-custom-components.solution.tsx} (100%) rename src/08-advanced-patterns/{72-as-prop-with-default.problem.tsx => 71-as-prop-with-default.problem.tsx} (100%) rename src/08-advanced-patterns/{72-as-prop-with-default.solution.1.tsx => 71-as-prop-with-default.solution.1.tsx} (100%) rename src/08-advanced-patterns/{72-as-prop-with-default.solution.2.tsx => 71-as-prop-with-default.solution.2.tsx} (100%) rename src/08-advanced-patterns/{73-as-prop-with-forward-ref.problem.tsx => 72-as-prop-with-forward-ref.problem.tsx} (100%) rename src/08-advanced-patterns/{73-as-prop-with-forward-ref.solution.tsx => 72-as-prop-with-forward-ref.solution.tsx} (100%) rename src/09-external-libraries/{74-react-hook-form.explainer.tsx => 73-react-hook-form.explainer.tsx} (100%) rename src/09-external-libraries/{75-react-hook-form-wrapper.problem.tsx => 74-react-hook-form-wrapper.problem.tsx} (100%) rename src/09-external-libraries/{75-react-hook-form-wrapper.solution.tsx => 74-react-hook-form-wrapper.solution.tsx} (100%) rename src/09-external-libraries/{76-react-select.problem.tsx => 75-react-select.problem.tsx} (100%) rename src/09-external-libraries/{76-react-select.solution.tsx => 75-react-select.solution.tsx} (100%) rename src/09-external-libraries/{77-react-query.explainer.ts => 76-react-query.explainer.ts} (100%) rename src/09-external-libraries/{78-react-query-wrapper.problem.ts => 77-react-query-wrapper.problem.ts} (100%) rename src/09-external-libraries/{78-react-query-wrapper.solution.ts => 77-react-query-wrapper.solution.ts} (100%) diff --git a/src/08-advanced-patterns/64-const-generics-in-generic-components.problem.tsx b/src/08-advanced-patterns/64-const-generics-in-generic-components.problem.tsx deleted file mode 100644 index 994484f..0000000 --- a/src/08-advanced-patterns/64-const-generics-in-generic-components.problem.tsx +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Have a Form component that can receive an object where - * the keys are the different form elements, and have the - * values inferred based on values passed in. - */ - -const Form = >() => {}; diff --git a/src/08-advanced-patterns/65-render-props.problem.tsx b/src/08-advanced-patterns/64-render-props.problem.tsx similarity index 100% rename from src/08-advanced-patterns/65-render-props.problem.tsx rename to src/08-advanced-patterns/64-render-props.problem.tsx diff --git a/src/08-advanced-patterns/65-render-props.solution.tsx b/src/08-advanced-patterns/64-render-props.solution.tsx similarity index 100% rename from src/08-advanced-patterns/65-render-props.solution.tsx rename to src/08-advanced-patterns/64-render-props.solution.tsx diff --git a/src/08-advanced-patterns/66-forward-ref-with-generics.explainer.1.tsx b/src/08-advanced-patterns/65-forward-ref-with-generics.explainer.1.tsx similarity index 100% rename from src/08-advanced-patterns/66-forward-ref-with-generics.explainer.1.tsx rename to src/08-advanced-patterns/65-forward-ref-with-generics.explainer.1.tsx diff --git a/src/08-advanced-patterns/66-forward-ref-with-generics.explainer.2.tsx b/src/08-advanced-patterns/65-forward-ref-with-generics.explainer.2.tsx similarity index 100% rename from src/08-advanced-patterns/66-forward-ref-with-generics.explainer.2.tsx rename to src/08-advanced-patterns/65-forward-ref-with-generics.explainer.2.tsx diff --git a/src/08-advanced-patterns/66-forward-ref-with-generics.explainer.3.ts b/src/08-advanced-patterns/65-forward-ref-with-generics.explainer.3.ts similarity index 100% rename from src/08-advanced-patterns/66-forward-ref-with-generics.explainer.3.ts rename to src/08-advanced-patterns/65-forward-ref-with-generics.explainer.3.ts diff --git a/src/08-advanced-patterns/67-forward-ref-as-local-function.problem.tsx b/src/08-advanced-patterns/66-forward-ref-as-local-function.problem.tsx similarity index 100% rename from src/08-advanced-patterns/67-forward-ref-as-local-function.problem.tsx rename to src/08-advanced-patterns/66-forward-ref-as-local-function.problem.tsx diff --git a/src/08-advanced-patterns/67-forward-ref-as-local-function.solution.1.tsx b/src/08-advanced-patterns/66-forward-ref-as-local-function.solution.1.tsx similarity index 100% rename from src/08-advanced-patterns/67-forward-ref-as-local-function.solution.1.tsx rename to src/08-advanced-patterns/66-forward-ref-as-local-function.solution.1.tsx diff --git a/src/08-advanced-patterns/67-forward-ref-as-local-function.solution.2.tsx b/src/08-advanced-patterns/66-forward-ref-as-local-function.solution.2.tsx similarity index 100% rename from src/08-advanced-patterns/67-forward-ref-as-local-function.solution.2.tsx rename to src/08-advanced-patterns/66-forward-ref-as-local-function.solution.2.tsx diff --git a/src/08-advanced-patterns/68-hoc.problem.tsx b/src/08-advanced-patterns/67-hoc.problem.tsx similarity index 100% rename from src/08-advanced-patterns/68-hoc.problem.tsx rename to src/08-advanced-patterns/67-hoc.problem.tsx diff --git a/src/08-advanced-patterns/68-hoc.solution.tsx b/src/08-advanced-patterns/67-hoc.solution.tsx similarity index 100% rename from src/08-advanced-patterns/68-hoc.solution.tsx rename to src/08-advanced-patterns/67-hoc.solution.tsx diff --git a/src/08-advanced-patterns/69-record-of-components-with-same-props.problem.tsx b/src/08-advanced-patterns/68-record-of-components-with-same-props.problem.tsx similarity index 100% rename from src/08-advanced-patterns/69-record-of-components-with-same-props.problem.tsx rename to src/08-advanced-patterns/68-record-of-components-with-same-props.problem.tsx diff --git a/src/08-advanced-patterns/69-record-of-components-with-same-props.solution.1.tsx b/src/08-advanced-patterns/68-record-of-components-with-same-props.solution.1.tsx similarity index 100% rename from src/08-advanced-patterns/69-record-of-components-with-same-props.solution.1.tsx rename to src/08-advanced-patterns/68-record-of-components-with-same-props.solution.1.tsx diff --git a/src/08-advanced-patterns/69-record-of-components-with-same-props.solution.2.tsx b/src/08-advanced-patterns/68-record-of-components-with-same-props.solution.2.tsx similarity index 100% rename from src/08-advanced-patterns/69-record-of-components-with-same-props.solution.2.tsx rename to src/08-advanced-patterns/68-record-of-components-with-same-props.solution.2.tsx diff --git a/src/08-advanced-patterns/70-as-prop.problem.tsx b/src/08-advanced-patterns/69-as-prop.problem.tsx similarity index 100% rename from src/08-advanced-patterns/70-as-prop.problem.tsx rename to src/08-advanced-patterns/69-as-prop.problem.tsx diff --git a/src/08-advanced-patterns/70-as-prop.solution.1.tsx b/src/08-advanced-patterns/69-as-prop.solution.1.tsx similarity index 100% rename from src/08-advanced-patterns/70-as-prop.solution.1.tsx rename to src/08-advanced-patterns/69-as-prop.solution.1.tsx diff --git a/src/08-advanced-patterns/70-as-prop.solution.2.tsx b/src/08-advanced-patterns/69-as-prop.solution.2.tsx similarity index 100% rename from src/08-advanced-patterns/70-as-prop.solution.2.tsx rename to src/08-advanced-patterns/69-as-prop.solution.2.tsx diff --git a/src/08-advanced-patterns/71-as-prop-with-custom-components.problem.tsx b/src/08-advanced-patterns/70-as-prop-with-custom-components.problem.tsx similarity index 100% rename from src/08-advanced-patterns/71-as-prop-with-custom-components.problem.tsx rename to src/08-advanced-patterns/70-as-prop-with-custom-components.problem.tsx diff --git a/src/08-advanced-patterns/71-as-prop-with-custom-components.solution.tsx b/src/08-advanced-patterns/70-as-prop-with-custom-components.solution.tsx similarity index 100% rename from src/08-advanced-patterns/71-as-prop-with-custom-components.solution.tsx rename to src/08-advanced-patterns/70-as-prop-with-custom-components.solution.tsx diff --git a/src/08-advanced-patterns/72-as-prop-with-default.problem.tsx b/src/08-advanced-patterns/71-as-prop-with-default.problem.tsx similarity index 100% rename from src/08-advanced-patterns/72-as-prop-with-default.problem.tsx rename to src/08-advanced-patterns/71-as-prop-with-default.problem.tsx diff --git a/src/08-advanced-patterns/72-as-prop-with-default.solution.1.tsx b/src/08-advanced-patterns/71-as-prop-with-default.solution.1.tsx similarity index 100% rename from src/08-advanced-patterns/72-as-prop-with-default.solution.1.tsx rename to src/08-advanced-patterns/71-as-prop-with-default.solution.1.tsx diff --git a/src/08-advanced-patterns/72-as-prop-with-default.solution.2.tsx b/src/08-advanced-patterns/71-as-prop-with-default.solution.2.tsx similarity index 100% rename from src/08-advanced-patterns/72-as-prop-with-default.solution.2.tsx rename to src/08-advanced-patterns/71-as-prop-with-default.solution.2.tsx diff --git a/src/08-advanced-patterns/73-as-prop-with-forward-ref.problem.tsx b/src/08-advanced-patterns/72-as-prop-with-forward-ref.problem.tsx similarity index 100% rename from src/08-advanced-patterns/73-as-prop-with-forward-ref.problem.tsx rename to src/08-advanced-patterns/72-as-prop-with-forward-ref.problem.tsx diff --git a/src/08-advanced-patterns/73-as-prop-with-forward-ref.solution.tsx b/src/08-advanced-patterns/72-as-prop-with-forward-ref.solution.tsx similarity index 100% rename from src/08-advanced-patterns/73-as-prop-with-forward-ref.solution.tsx rename to src/08-advanced-patterns/72-as-prop-with-forward-ref.solution.tsx diff --git a/src/09-external-libraries/74-react-hook-form.explainer.tsx b/src/09-external-libraries/73-react-hook-form.explainer.tsx similarity index 100% rename from src/09-external-libraries/74-react-hook-form.explainer.tsx rename to src/09-external-libraries/73-react-hook-form.explainer.tsx diff --git a/src/09-external-libraries/75-react-hook-form-wrapper.problem.tsx b/src/09-external-libraries/74-react-hook-form-wrapper.problem.tsx similarity index 100% rename from src/09-external-libraries/75-react-hook-form-wrapper.problem.tsx rename to src/09-external-libraries/74-react-hook-form-wrapper.problem.tsx diff --git a/src/09-external-libraries/75-react-hook-form-wrapper.solution.tsx b/src/09-external-libraries/74-react-hook-form-wrapper.solution.tsx similarity index 100% rename from src/09-external-libraries/75-react-hook-form-wrapper.solution.tsx rename to src/09-external-libraries/74-react-hook-form-wrapper.solution.tsx diff --git a/src/09-external-libraries/76-react-select.problem.tsx b/src/09-external-libraries/75-react-select.problem.tsx similarity index 100% rename from src/09-external-libraries/76-react-select.problem.tsx rename to src/09-external-libraries/75-react-select.problem.tsx diff --git a/src/09-external-libraries/76-react-select.solution.tsx b/src/09-external-libraries/75-react-select.solution.tsx similarity index 100% rename from src/09-external-libraries/76-react-select.solution.tsx rename to src/09-external-libraries/75-react-select.solution.tsx diff --git a/src/09-external-libraries/77-react-query.explainer.ts b/src/09-external-libraries/76-react-query.explainer.ts similarity index 100% rename from src/09-external-libraries/77-react-query.explainer.ts rename to src/09-external-libraries/76-react-query.explainer.ts diff --git a/src/09-external-libraries/78-react-query-wrapper.problem.ts b/src/09-external-libraries/77-react-query-wrapper.problem.ts similarity index 100% rename from src/09-external-libraries/78-react-query-wrapper.problem.ts rename to src/09-external-libraries/77-react-query-wrapper.problem.ts diff --git a/src/09-external-libraries/78-react-query-wrapper.solution.ts b/src/09-external-libraries/77-react-query-wrapper.solution.ts similarity index 100% rename from src/09-external-libraries/78-react-query-wrapper.solution.ts rename to src/09-external-libraries/77-react-query-wrapper.solution.ts From 59cbbfd03451375b2f94cb2ad4e39f488388beab Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 24 Jul 2023 15:51:28 +0100 Subject: [PATCH 034/105] Finished 64 --- src/08-advanced-patterns/64-render-props.solution.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/08-advanced-patterns/64-render-props.solution.tsx b/src/08-advanced-patterns/64-render-props.solution.tsx index 8b3ffc1..f88116a 100644 --- a/src/08-advanced-patterns/64-render-props.solution.tsx +++ b/src/08-advanced-patterns/64-render-props.solution.tsx @@ -8,11 +8,7 @@ interface ModalChildProps { closeModal: () => void; } -const Modal = ({ - children, -}: { - children: (props: ModalChildProps) => React.ReactNode; -}) => { +const Modal = ({ children }: { children: React.FC }) => { const [isOpen, setIsOpen] = useState(false); return ( From aa556e7aae837cde2a8c04e772dda1a624c2284a Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 24 Jul 2023 15:54:11 +0100 Subject: [PATCH 035/105] Added more tests to forwardRef explainer --- ...-forward-ref-with-generics.explainer.1.tsx | 36 +++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/08-advanced-patterns/65-forward-ref-with-generics.explainer.1.tsx b/src/08-advanced-patterns/65-forward-ref-with-generics.explainer.1.tsx index 8f96727..a0a1042 100644 --- a/src/08-advanced-patterns/65-forward-ref-with-generics.explainer.1.tsx +++ b/src/08-advanced-patterns/65-forward-ref-with-generics.explainer.1.tsx @@ -1,4 +1,4 @@ -import { ForwardedRef, forwardRef } from "react"; +import { ForwardedRef, forwardRef, useRef } from "react"; import { Equal, Expect } from "../helpers/type-utils"; type Props = { @@ -31,20 +31,36 @@ type Props = { * By doing it this way, we preserve the generic context of the function * being passed in. */ -export const Table = (props: Props, ref: ForwardedRef) => { - return null; +export const Table = ( + props: Props, + ref: ForwardedRef, +) => { + return ; }; const ForwardReffedTable = forwardRef(Table); const Parent = () => { + const tableRef = useRef(null); + const wrongRef = useRef(null); return ( - { - type test = Expect>; - return
123
; - }} - >
+ <> + { + type test = Expect>; + return
123
; + }} + /> + { + return
123
; + }} + /> + ); }; From 173aad5883a4a2c3c63ee3f9f04e15b860870954 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 24 Jul 2023 16:32:40 +0100 Subject: [PATCH 036/105] Fixed 66 example --- ...-forward-ref-as-local-function.problem.tsx | 36 +++++++++++++------ ...rward-ref-as-local-function.solution.1.tsx | 36 +++++++++++++------ ...rward-ref-as-local-function.solution.2.tsx | 34 +++++++++++++----- 3 files changed, 77 insertions(+), 29 deletions(-) diff --git a/src/08-advanced-patterns/66-forward-ref-as-local-function.problem.tsx b/src/08-advanced-patterns/66-forward-ref-as-local-function.problem.tsx index e78bbaf..c6931fb 100644 --- a/src/08-advanced-patterns/66-forward-ref-as-local-function.problem.tsx +++ b/src/08-advanced-patterns/66-forward-ref-as-local-function.problem.tsx @@ -1,4 +1,4 @@ -import { ForwardedRef, forwardRef } from "react"; +import { ForwardedRef, forwardRef, useRef } from "react"; import { Equal, Expect } from "../helpers/type-utils"; /** @@ -17,20 +17,36 @@ type Props = { renderRow: (item: T) => React.ReactNode; }; -export const Table = (props: Props, ref: ForwardedRef) => { - return null; +export const Table = ( + props: Props, + ref: ForwardedRef, +) => { + return
; }; const ForwardReffedTable = fixedForwardRef(Table); const Parent = () => { + const tableRef = useRef(null); + const wrongRef = useRef(null); return ( - { - type test = Expect>; - return
123
; - }} - >
+ <> + { + type test = Expect>; + return
123
; + }} + /> + { + return
123
; + }} + /> + ); }; diff --git a/src/08-advanced-patterns/66-forward-ref-as-local-function.solution.1.tsx b/src/08-advanced-patterns/66-forward-ref-as-local-function.solution.1.tsx index 9c4652c..9a7a82d 100644 --- a/src/08-advanced-patterns/66-forward-ref-as-local-function.solution.1.tsx +++ b/src/08-advanced-patterns/66-forward-ref-as-local-function.solution.1.tsx @@ -1,4 +1,4 @@ -import { ForwardedRef, forwardRef } from "react"; +import { ForwardedRef, forwardRef, useRef } from "react"; import { Equal, Expect } from "../helpers/type-utils"; function fixedForwardRef( @@ -12,20 +12,36 @@ type Props = { renderRow: (item: T) => React.ReactNode; }; -export const Table = (props: Props, ref: ForwardedRef) => { - return null; +export const Table = ( + props: Props, + ref: ForwardedRef, +) => { + return
; }; const ForwardReffedTable = fixedForwardRef(Table); const Parent = () => { + const tableRef = useRef(null); + const wrongRef = useRef(null); return ( - { - type test = Expect>; - return
123
; - }} - >
+ <> + { + type test = Expect>; + return
123
; + }} + /> + { + return
123
; + }} + /> + ); }; diff --git a/src/08-advanced-patterns/66-forward-ref-as-local-function.solution.2.tsx b/src/08-advanced-patterns/66-forward-ref-as-local-function.solution.2.tsx index 37ae3f0..3678aec 100644 --- a/src/08-advanced-patterns/66-forward-ref-as-local-function.solution.2.tsx +++ b/src/08-advanced-patterns/66-forward-ref-as-local-function.solution.2.tsx @@ -13,20 +13,36 @@ type Props = { renderRow: (item: T) => React.ReactNode; }; -export const Table = (props: Props, ref: ForwardedRef) => { - return null; +export const Table = ( + props: Props, + ref: ForwardedRef, +) => { + return
; }; const ForwardReffedTable = fixedForwardRef(Table); const Parent = () => { + const tableRef = useRef(null); + const wrongRef = useRef(null); return ( - { - type test = Expect>; - return
123
; - }} - >
+ <> + { + type test = Expect>; + return
123
; + }} + /> + { + return
123
; + }} + /> + ); }; From 6b7e99d6cb2776aeffd222adb37891ecf41f6d63 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 24 Jul 2023 16:37:43 +0100 Subject: [PATCH 037/105] Fixed 66 --- .../66-forward-ref-as-local-function.solution.2.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/08-advanced-patterns/66-forward-ref-as-local-function.solution.2.tsx b/src/08-advanced-patterns/66-forward-ref-as-local-function.solution.2.tsx index 3678aec..785c13c 100644 --- a/src/08-advanced-patterns/66-forward-ref-as-local-function.solution.2.tsx +++ b/src/08-advanced-patterns/66-forward-ref-as-local-function.solution.2.tsx @@ -1,6 +1,6 @@ import { Equal, Expect } from "../helpers/type-utils"; -import { ForwardedRef, forwardRef } from "react"; +import { ForwardedRef, forwardRef, useRef } from "react"; type FixedForwardRef = ( render: (props: P, ref: React.Ref) => React.ReactNode, From 2fd10e76bfd520b8e6959853f6a7e885c3694f00 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 7 Aug 2023 10:39:16 +0100 Subject: [PATCH 038/105] Removed ElementRef from 66 --- .../66-forward-ref-as-local-function.solution.2.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/08-advanced-patterns/66-forward-ref-as-local-function.solution.2.tsx b/src/08-advanced-patterns/66-forward-ref-as-local-function.solution.2.tsx index 785c13c..9a25ebc 100644 --- a/src/08-advanced-patterns/66-forward-ref-as-local-function.solution.2.tsx +++ b/src/08-advanced-patterns/66-forward-ref-as-local-function.solution.2.tsx @@ -1,6 +1,6 @@ import { Equal, Expect } from "../helpers/type-utils"; -import { ForwardedRef, forwardRef, useRef } from "react"; +import { ElementRef, ForwardedRef, forwardRef, useRef } from "react"; type FixedForwardRef = ( render: (props: P, ref: React.Ref) => React.ReactNode, From a080f2404d7624b1e9c3bc88d4cd946f344781f9 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 7 Aug 2023 10:39:51 +0100 Subject: [PATCH 039/105] Removed ElementRef --- .../66-forward-ref-as-local-function.solution.2.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/08-advanced-patterns/66-forward-ref-as-local-function.solution.2.tsx b/src/08-advanced-patterns/66-forward-ref-as-local-function.solution.2.tsx index 9a25ebc..785c13c 100644 --- a/src/08-advanced-patterns/66-forward-ref-as-local-function.solution.2.tsx +++ b/src/08-advanced-patterns/66-forward-ref-as-local-function.solution.2.tsx @@ -1,6 +1,6 @@ import { Equal, Expect } from "../helpers/type-utils"; -import { ElementRef, ForwardedRef, forwardRef, useRef } from "react"; +import { ForwardedRef, forwardRef, useRef } from "react"; type FixedForwardRef = ( render: (props: P, ref: React.Ref) => React.ReactNode, From 50acd9be41ccf4bb1faf2c2e2151717cb83a33ab Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 7 Aug 2023 10:46:01 +0100 Subject: [PATCH 040/105] Improved forwardRef with generics explainer --- ...5-forward-ref-with-generics.explainer.3.ts | 63 ------------------- ...-forward-ref-with-generics.explainer.3.tsx | 46 ++++++++++++++ 2 files changed, 46 insertions(+), 63 deletions(-) delete mode 100644 src/08-advanced-patterns/65-forward-ref-with-generics.explainer.3.ts create mode 100644 src/08-advanced-patterns/65-forward-ref-with-generics.explainer.3.tsx diff --git a/src/08-advanced-patterns/65-forward-ref-with-generics.explainer.3.ts b/src/08-advanced-patterns/65-forward-ref-with-generics.explainer.3.ts deleted file mode 100644 index 873f796..0000000 --- a/src/08-advanced-patterns/65-forward-ref-with-generics.explainer.3.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { Equal, Expect } from "../helpers/type-utils"; - -/** - * Here's a detailed breakdown on why forwardRef doesn't work. - */ - -/** - * 1. We create a type that represents a function, but with - * some other attributes. - */ -type FuncExpected = { - (arg: Argument): Argument; - someOtherThing?: string; -}; - -/** - * 2. We create a function that takes a function as an argument, - * and infers the position of Argument. - * - * This function doesn't do anything at runtime - it just returns - * the function that was passed in. But it behaves similarly to - * forwardRef. - */ -const forwardRefShim = (func: FuncExpected) => { - return (arg: Argument) => func(arg); -}; - -/** - * 3. We create an identity function, that just takes in an argument - * and returns it. - */ -const identityFunc = (arg: Argument) => { - return arg; -}; - -/** - * 4. As you can see, when it's not wrapped, identityFunc returns - * the type that we pass in, 123. - */ -const result1 = identityFunc(123); - -type test1 = Expect>; - -/** - * 5. But when we wrap it in forwardRefShim, it loses its powers - * of inference! Just like forwardRef. - */ -const wrappedIdentityFunc = forwardRefShim(identityFunc); - -const result2 = wrappedIdentityFunc(123); - -type test2 = Expect>; - -/** - * 6. Here's the really crazy part. Go back up to FuncExpected. - * Comment out the someOtherThing property. - * - * It now works! This is because when a function is _just_ a function, - * TypeScript uses its higher-order function powers on it. But when - * it has other properties, it doesn't. - * - * Bizarre! - */ diff --git a/src/08-advanced-patterns/65-forward-ref-with-generics.explainer.3.tsx b/src/08-advanced-patterns/65-forward-ref-with-generics.explainer.3.tsx new file mode 100644 index 0000000..40fb1ed --- /dev/null +++ b/src/08-advanced-patterns/65-forward-ref-with-generics.explainer.3.tsx @@ -0,0 +1,46 @@ +import { Equal, Expect } from "../helpers/type-utils"; + +type TableProps = { + data: T[]; + renderRow: (item: T) => React.ReactNode; +}; + +export const Table = (props: TableProps) => { + return null; +}; + +type FC = { + (arg: Props): React.ReactNode; + // Try uncommenting this - and it works! + someOtherThing?: string; +}; + +const removeInference = (component: FC) => { + return component; +}; + +const TableWithoutInference = removeInference(Table); + +const Parent = () => { + return ( + <> + { + // Without inference, this is 'unknown' + type test = Expect>; + return
123
; + }} + >
+ +
{ + // With inference, it's 'string' + type test = Expect>; + return
123
; + }} + >
+ + ); +}; From ed9bf17f188be0473213beb3054721868d60f1eb Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 7 Aug 2023 13:26:11 +0100 Subject: [PATCH 041/105] Changed HOC problem --- src/08-advanced-patterns/67-hoc.problem.tsx | 15 ----- ...7.5-hoc-for-generic-components.problem.tsx | 54 ++++++++++++++++++ ....5-hoc-for-generic-components.solution.tsx | 56 +++++++++++++++++++ 3 files changed, 110 insertions(+), 15 deletions(-) create mode 100644 src/08-advanced-patterns/67.5-hoc-for-generic-components.problem.tsx create mode 100644 src/08-advanced-patterns/67.5-hoc-for-generic-components.solution.tsx diff --git a/src/08-advanced-patterns/67-hoc.problem.tsx b/src/08-advanced-patterns/67-hoc.problem.tsx index fa071f1..70e4167 100644 --- a/src/08-advanced-patterns/67-hoc.problem.tsx +++ b/src/08-advanced-patterns/67-hoc.problem.tsx @@ -1,20 +1,5 @@ import { Router, useRouter } from "fake-external-lib"; -/** - * A higher-order component is a function that takes a component and returns a - * new component, with some additional props/behavior. - * - * In this case, we want to take a component that doesn't have a router prop, - * and add one. - * - * 1. Figure out the correct typings for the `withRouter` function. You'll - * need to use: - * - * - Generics - * - Omit - * - React.ComponentType - * - Probably an 'as' at least once - */ export const withRouter = (Component: any) => { const NewComponent = (props: any) => { const router = useRouter(); diff --git a/src/08-advanced-patterns/67.5-hoc-for-generic-components.problem.tsx b/src/08-advanced-patterns/67.5-hoc-for-generic-components.problem.tsx new file mode 100644 index 0000000..18a2a4e --- /dev/null +++ b/src/08-advanced-patterns/67.5-hoc-for-generic-components.problem.tsx @@ -0,0 +1,54 @@ +import { Router, useRouter } from "fake-external-lib"; +import { Equal, Expect } from "../helpers/type-utils"; + +export const withRouter = ( + Component: React.FC, +) => { + const NewComponent = (props: Omit) => { + const router = useRouter(); + return ; + }; + + NewComponent.displayName = `withRouter(${Component.displayName})`; + + return NewComponent; +}; + +type TableProps = { + data: T[]; + renderRow: (item: T) => React.ReactNode; + router: Router; +}; + +export const Table = (props: TableProps) => { + return ; +}; + +const WrappedTable = withRouter(Table); + +<> + {/* @ts-expect-error router is required! */} +
{ + type test = Expect>; + return ; + }} + /> + + { + type test = Expect>; + return ; + }} + /> + + { + type test = Expect>; + return ; + }} + /> +; diff --git a/src/08-advanced-patterns/67.5-hoc-for-generic-components.solution.tsx b/src/08-advanced-patterns/67.5-hoc-for-generic-components.solution.tsx new file mode 100644 index 0000000..bb324d4 --- /dev/null +++ b/src/08-advanced-patterns/67.5-hoc-for-generic-components.solution.tsx @@ -0,0 +1,56 @@ +import { Router, useRouter } from "fake-external-lib"; +import { Equal, Expect } from "../helpers/type-utils"; + +export const withRouter = ( + Component: (props: TProps) => React.ReactNode, +): ((props: Omit) => React.ReactNode) => { + const NewComponent = (props: Omit) => { + const router = useRouter(); + return ; + }; + + NewComponent.displayName = `withRouter(${ + (Component as { displayName?: string }).displayName + })`; + + return NewComponent; +}; + +type TableProps = { + data: T[]; + renderRow: (item: T) => React.ReactNode; + router: Router; +}; + +export const Table = (props: TableProps) => { + return
; +}; + +const WrappedTable = withRouter(Table); + +<> + {/* @ts-expect-error router is required! */} +
{ + type test = Expect>; + return ; + }} + /> + + { + type test = Expect>; + return ; + }} + /> + + { + type test = Expect>; + return ; + }} + /> +; From bb55b6b205e5d08bb4558c806b84625d6edfde90 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 7 Aug 2023 13:33:43 +0100 Subject: [PATCH 042/105] Finished HOC --- src/08-advanced-patterns/67-hoc.solution.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/08-advanced-patterns/67-hoc.solution.tsx b/src/08-advanced-patterns/67-hoc.solution.tsx index 2cb7942..4a3dc0a 100644 --- a/src/08-advanced-patterns/67-hoc.solution.tsx +++ b/src/08-advanced-patterns/67-hoc.solution.tsx @@ -1,8 +1,6 @@ import { Router, useRouter } from "fake-external-lib"; -export const withRouter = ( - Component: React.FC, -) => { +export const withRouter = (Component: React.ComponentType) => { const NewComponent = (props: Omit) => { const router = useRouter(); return ; From 0b4eee4371425002d707cc429e199e0299dc8192 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 7 Aug 2023 13:36:30 +0100 Subject: [PATCH 043/105] Fixed 67.5 --- .../67.5-hoc-for-generic-components.problem.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/08-advanced-patterns/67.5-hoc-for-generic-components.problem.tsx b/src/08-advanced-patterns/67.5-hoc-for-generic-components.problem.tsx index 18a2a4e..781037c 100644 --- a/src/08-advanced-patterns/67.5-hoc-for-generic-components.problem.tsx +++ b/src/08-advanced-patterns/67.5-hoc-for-generic-components.problem.tsx @@ -1,9 +1,7 @@ import { Router, useRouter } from "fake-external-lib"; import { Equal, Expect } from "../helpers/type-utils"; -export const withRouter = ( - Component: React.FC, -) => { +export const withRouter = (Component: React.ComponentType) => { const NewComponent = (props: Omit) => { const router = useRouter(); return ; From 7a6ad76a85ddc078a7f8669d2235588fac97393b Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 7 Aug 2023 13:49:44 +0100 Subject: [PATCH 044/105] Completed 67.5 --- .../67.5-hoc-for-generic-components.solution.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/08-advanced-patterns/67.5-hoc-for-generic-components.solution.tsx b/src/08-advanced-patterns/67.5-hoc-for-generic-components.solution.tsx index bb324d4..ffd22d9 100644 --- a/src/08-advanced-patterns/67.5-hoc-for-generic-components.solution.tsx +++ b/src/08-advanced-patterns/67.5-hoc-for-generic-components.solution.tsx @@ -1,7 +1,7 @@ import { Router, useRouter } from "fake-external-lib"; import { Equal, Expect } from "../helpers/type-utils"; -export const withRouter = ( +export const withRouter = ( Component: (props: TProps) => React.ReactNode, ): ((props: Omit) => React.ReactNode) => { const NewComponent = (props: Omit) => { @@ -10,7 +10,11 @@ export const withRouter = ( }; NewComponent.displayName = `withRouter(${ - (Component as { displayName?: string }).displayName + ( + Component as { + displayName?: string; + } + ).displayName })`; return NewComponent; From b460e6a27f80de451c6f033b405a046f0bc52c03 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 7 Aug 2023 13:50:39 +0100 Subject: [PATCH 045/105] Changed 68 to 64.5 --- ....tsx => 64.5-record-of-components-with-same-props.problem.tsx} | 0 ...x => 64.5-record-of-components-with-same-props.solution.1.tsx} | 0 ...x => 64.5-record-of-components-with-same-props.solution.2.tsx} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename src/08-advanced-patterns/{68-record-of-components-with-same-props.problem.tsx => 64.5-record-of-components-with-same-props.problem.tsx} (100%) rename src/08-advanced-patterns/{68-record-of-components-with-same-props.solution.1.tsx => 64.5-record-of-components-with-same-props.solution.1.tsx} (100%) rename src/08-advanced-patterns/{68-record-of-components-with-same-props.solution.2.tsx => 64.5-record-of-components-with-same-props.solution.2.tsx} (100%) diff --git a/src/08-advanced-patterns/68-record-of-components-with-same-props.problem.tsx b/src/08-advanced-patterns/64.5-record-of-components-with-same-props.problem.tsx similarity index 100% rename from src/08-advanced-patterns/68-record-of-components-with-same-props.problem.tsx rename to src/08-advanced-patterns/64.5-record-of-components-with-same-props.problem.tsx diff --git a/src/08-advanced-patterns/68-record-of-components-with-same-props.solution.1.tsx b/src/08-advanced-patterns/64.5-record-of-components-with-same-props.solution.1.tsx similarity index 100% rename from src/08-advanced-patterns/68-record-of-components-with-same-props.solution.1.tsx rename to src/08-advanced-patterns/64.5-record-of-components-with-same-props.solution.1.tsx diff --git a/src/08-advanced-patterns/68-record-of-components-with-same-props.solution.2.tsx b/src/08-advanced-patterns/64.5-record-of-components-with-same-props.solution.2.tsx similarity index 100% rename from src/08-advanced-patterns/68-record-of-components-with-same-props.solution.2.tsx rename to src/08-advanced-patterns/64.5-record-of-components-with-same-props.solution.2.tsx From 2fab9b0ff08daca5a51944c760b812dee4bff744 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 7 Aug 2023 16:33:53 +0100 Subject: [PATCH 046/105] Fixed 69 --- src/08-advanced-patterns/69-as-prop.solution.1.tsx | 13 ++++++++----- src/08-advanced-patterns/69-as-prop.solution.2.tsx | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/08-advanced-patterns/69-as-prop.solution.1.tsx b/src/08-advanced-patterns/69-as-prop.solution.1.tsx index 939c576..3d7d67a 100644 --- a/src/08-advanced-patterns/69-as-prop.solution.1.tsx +++ b/src/08-advanced-patterns/69-as-prop.solution.1.tsx @@ -1,10 +1,13 @@ import { Equal, Expect } from "../helpers/type-utils"; -type AsProps = { - [K in keyof JSX.IntrinsicElements]: { - as: K; - } & JSX.IntrinsicElements[K]; -}[keyof JSX.IntrinsicElements]; +// Commented out because it makes the whole repo slow to typecheck +// Uncomment to see it working! + +// type AsProps = { +// [K in keyof JSX.IntrinsicElements]: { +// as: K; +// } & JSX.IntrinsicElements[K]; +// }[keyof JSX.IntrinsicElements]; export const Wrapper = (props: AsProps) => { const Comp = props.as; diff --git a/src/08-advanced-patterns/69-as-prop.solution.2.tsx b/src/08-advanced-patterns/69-as-prop.solution.2.tsx index d2729ad..089ae87 100644 --- a/src/08-advanced-patterns/69-as-prop.solution.2.tsx +++ b/src/08-advanced-patterns/69-as-prop.solution.2.tsx @@ -3,7 +3,7 @@ import { Equal, Expect } from "../helpers/type-utils"; export const Wrapper = ( props: { as: TAs; - } & JSX.IntrinsicElements[TAs], + } & React.ComponentProps, ) => { const Comp = props.as as string; From 76f2a1d3b4fe4df3bd336869554579363732b1d4 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 7 Aug 2023 16:37:50 +0100 Subject: [PATCH 047/105] Fixed custom component --- .../70-as-prop-with-custom-components.problem.tsx | 7 ++----- .../70-as-prop-with-custom-components.solution.tsx | 7 ++----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/08-advanced-patterns/70-as-prop-with-custom-components.problem.tsx b/src/08-advanced-patterns/70-as-prop-with-custom-components.problem.tsx index dc2c983..197b258 100644 --- a/src/08-advanced-patterns/70-as-prop-with-custom-components.problem.tsx +++ b/src/08-advanced-patterns/70-as-prop-with-custom-components.problem.tsx @@ -45,11 +45,8 @@ const Example1 = () => { * Should work with Custom components! */ -const Custom = ( - props: { thisIsRequired: boolean }, - ref: React.ForwardedRef, -) => { - return ; +const Custom = (props: { thisIsRequired: boolean }) => { + return ; }; const Example2 = () => { diff --git a/src/08-advanced-patterns/70-as-prop-with-custom-components.solution.tsx b/src/08-advanced-patterns/70-as-prop-with-custom-components.solution.tsx index be6635a..95dc6ec 100644 --- a/src/08-advanced-patterns/70-as-prop-with-custom-components.solution.tsx +++ b/src/08-advanced-patterns/70-as-prop-with-custom-components.solution.tsx @@ -40,11 +40,8 @@ const Example1 = () => { * Should work with Custom components! */ -const Custom = ( - props: { thisIsRequired: boolean }, - ref: React.ForwardedRef, -) => { - return ; +const Custom = (props: { thisIsRequired: boolean }) => { + return ; }; const Example2 = () => { From 782759d01b25b8cbe9493c6b4afe690f2ed43e18 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 7 Aug 2023 16:44:39 +0100 Subject: [PATCH 048/105] Added extra detail to the comment --- .../70-as-prop-with-custom-components.problem.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/08-advanced-patterns/70-as-prop-with-custom-components.problem.tsx b/src/08-advanced-patterns/70-as-prop-with-custom-components.problem.tsx index 197b258..3850d0b 100644 --- a/src/08-advanced-patterns/70-as-prop-with-custom-components.problem.tsx +++ b/src/08-advanced-patterns/70-as-prop-with-custom-components.problem.tsx @@ -8,7 +8,14 @@ import { Equal, Expect } from "../helpers/type-utils"; * * 1. Figure out the correct typings for the `Wrapper` component. * - * The solution uses generics, and the ComponentType helper. + * The solution uses: + * + * - Generics + * - ElementType + * - One of the following: + * - ComponentPropsWithoutRef + * - ComponentPropsWithRef + * - ComponentProps */ export const Wrapper = (props: { as: unknown }) => { const Comp = props.as; From 9ac77a12b5e698bdece3f7cdc1ba21c37ea6a4e1 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 7 Aug 2023 16:45:14 +0100 Subject: [PATCH 049/105] Changed the way that 70 starts out --- .../70-as-prop-with-custom-components.problem.tsx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/08-advanced-patterns/70-as-prop-with-custom-components.problem.tsx b/src/08-advanced-patterns/70-as-prop-with-custom-components.problem.tsx index 3850d0b..fbd721f 100644 --- a/src/08-advanced-patterns/70-as-prop-with-custom-components.problem.tsx +++ b/src/08-advanced-patterns/70-as-prop-with-custom-components.problem.tsx @@ -17,9 +17,14 @@ import { Equal, Expect } from "../helpers/type-utils"; * - ComponentPropsWithRef * - ComponentProps */ -export const Wrapper = (props: { as: unknown }) => { - const Comp = props.as; - return ; +export const Wrapper = ( + props: { + as: TAs; + } & React.ComponentProps, +) => { + const Comp = props.as as string; + + return ; }; /** From 35b5af3abfdf8caf4dda11bb79c5abbbce9281c3 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Tue, 8 Aug 2023 09:02:34 +0100 Subject: [PATCH 050/105] Changed 70 solution --- .../70-as-prop-with-custom-components.solution.tsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/08-advanced-patterns/70-as-prop-with-custom-components.solution.tsx b/src/08-advanced-patterns/70-as-prop-with-custom-components.solution.tsx index 95dc6ec..e4238f4 100644 --- a/src/08-advanced-patterns/70-as-prop-with-custom-components.solution.tsx +++ b/src/08-advanced-patterns/70-as-prop-with-custom-components.solution.tsx @@ -1,12 +1,13 @@ -import React, { ComponentPropsWithoutRef, ElementType } from "react"; +import React, { ElementType } from "react"; import { Equal, Expect } from "../helpers/type-utils"; -export const Wrapper = ( +export const Wrapper = ( props: { - as: T; - } & ComponentPropsWithoutRef, + as: TAs; + } & React.ComponentPropsWithoutRef, ) => { const Comp = props.as; + return ; }; From 2ca5d6b11536ee6803125b54871a87122261ad5e Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Tue, 8 Aug 2023 09:33:26 +0100 Subject: [PATCH 051/105] Changed the start of 71 --- .../71-as-prop-with-default.problem.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/08-advanced-patterns/71-as-prop-with-default.problem.tsx b/src/08-advanced-patterns/71-as-prop-with-default.problem.tsx index 9be70e8..28b2e79 100644 --- a/src/08-advanced-patterns/71-as-prop-with-default.problem.tsx +++ b/src/08-advanced-patterns/71-as-prop-with-default.problem.tsx @@ -1,13 +1,13 @@ -import { ComponentPropsWithoutRef, ElementType } from "react"; +import { ElementType } from "react"; import { Equal, Expect } from "../helpers/type-utils"; -export const Link = ( +export const Link = ( props: { - as: T; - } & ComponentPropsWithoutRef, + as: TAs; + } & React.ComponentPropsWithoutRef, ) => { - const Comp = props.as; - return ; + const { as: Comp = "a", ...rest } = props; + return ; }; /** From 27a1313689c4137b3770d081893f80bc923d12c9 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Tue, 8 Aug 2023 09:48:31 +0100 Subject: [PATCH 052/105] Improved 72 --- .../72-as-prop-with-forward-ref.problem.tsx | 10 ++++++---- .../72-as-prop-with-forward-ref.solution.tsx | 11 +++++++++-- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/08-advanced-patterns/72-as-prop-with-forward-ref.problem.tsx b/src/08-advanced-patterns/72-as-prop-with-forward-ref.problem.tsx index bf28cd4..f05136d 100644 --- a/src/08-advanced-patterns/72-as-prop-with-forward-ref.problem.tsx +++ b/src/08-advanced-patterns/72-as-prop-with-forward-ref.problem.tsx @@ -1,6 +1,7 @@ import { ComponentPropsWithoutRef, ElementType, + ForwardedRef, forwardRef, useRef, } from "react"; @@ -13,13 +14,14 @@ import { Equal, Expect } from "../helpers/type-utils"; * So, don't feel bad if you don't find it at all. */ -export const UnwrappedLink = ( +export const UnwrappedLink = ( props: { - as?: T; - } & ComponentPropsWithoutRef, + as?: TAs; + } & ComponentPropsWithoutRef, + ref: ForwardedRef, ) => { const { as: Comp = "a", ...rest } = props; - return ; + return ; }; const Link = forwardRef(UnwrappedLink); diff --git a/src/08-advanced-patterns/72-as-prop-with-forward-ref.solution.tsx b/src/08-advanced-patterns/72-as-prop-with-forward-ref.solution.tsx index 9b5d9f2..4a6f479 100644 --- a/src/08-advanced-patterns/72-as-prop-with-forward-ref.solution.tsx +++ b/src/08-advanced-patterns/72-as-prop-with-forward-ref.solution.tsx @@ -1,4 +1,10 @@ -import { ComponentProps, ElementType, forwardRef, useRef } from "react"; +import { + ComponentProps, + ElementType, + ForwardedRef, + forwardRef, + useRef, +} from "react"; import { Equal, Expect } from "../helpers/type-utils"; // Added fixedForwardRef from a previous exercise @@ -19,9 +25,10 @@ function UnwrappedLink( props: { as?: T; } & DistributiveOmit, "as">, + ref: ForwardedRef, ) { const { as: Comp = "a", ...rest } = props; - return ; + return ; } const Link = fixedForwardRef(UnwrappedLink); From aa01465315300f8504f8de6e7ee9764c54d8db4b Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Tue, 8 Aug 2023 10:09:59 +0100 Subject: [PATCH 053/105] Fixed 72 --- .../72-as-prop-with-forward-ref.solution.tsx | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/08-advanced-patterns/72-as-prop-with-forward-ref.solution.tsx b/src/08-advanced-patterns/72-as-prop-with-forward-ref.solution.tsx index 4a6f479..5b915de 100644 --- a/src/08-advanced-patterns/72-as-prop-with-forward-ref.solution.tsx +++ b/src/08-advanced-patterns/72-as-prop-with-forward-ref.solution.tsx @@ -1,5 +1,5 @@ import { - ComponentProps, + ComponentPropsWithRef, ElementType, ForwardedRef, forwardRef, @@ -21,15 +21,18 @@ type DistributiveOmit = T extends any ? Omit : never; -function UnwrappedLink( +export const UnwrappedLink = ( props: { - as?: T; - } & DistributiveOmit, "as">, + as?: TAs; + } & DistributiveOmit< + ComponentPropsWithRef, + "as" + >, ref: ForwardedRef, -) { +) => { const { as: Comp = "a", ...rest } = props; return ; -} +}; const Link = fixedForwardRef(UnwrappedLink); From 616b92de88d47d0a40a81c3f0c12db606fce592f Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 14 Aug 2023 14:08:58 +0100 Subject: [PATCH 054/105] Removed dead file --- ...42-passing-types-to-components.problem.tsx | 58 ------------------- 1 file changed, 58 deletions(-) delete mode 100644 src/05-generics/42-passing-types-to-components.problem.tsx diff --git a/src/05-generics/42-passing-types-to-components.problem.tsx b/src/05-generics/42-passing-types-to-components.problem.tsx deleted file mode 100644 index 5bba74e..0000000 --- a/src/05-generics/42-passing-types-to-components.problem.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import { ReactNode } from "react"; -import { Equal, Expect } from "../helpers/type-utils"; - -interface TableProps { - rows: T[]; - renderRow: (row: T) => ReactNode; -} - -export const Table = (props: TableProps) => { - return ( -
- - {props.rows.map((row) => ( - {props.renderRow(row)} - ))} - -
- ); -}; - -interface User { - id: number; - name: string; - age: number; -} - -/** - * Below, we'd love to ensure that the type of `row` is `User`. How - * do we do this? - */ -<> - { - type test = Expect>; - return ; - }} - /> -
{row.name}
{ - type test = Expect>; - return ; - }} - >
{row.name}
-; From 716502ded0b4a17ca09d5f5618a13d815ddd17c0 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 21 Aug 2023 12:47:13 +0100 Subject: [PATCH 055/105] Improved explainer --- .../73-react-hook-form.explainer.tsx | 48 +++++++++++++------ 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/src/09-external-libraries/73-react-hook-form.explainer.tsx b/src/09-external-libraries/73-react-hook-form.explainer.tsx index 60d4f29..1c6e0e9 100644 --- a/src/09-external-libraries/73-react-hook-form.explainer.tsx +++ b/src/09-external-libraries/73-react-hook-form.explainer.tsx @@ -7,18 +7,27 @@ import { Equal, Expect } from "../helpers/type-utils"; * * Investigate why this is, and what TFieldValues is being used for. */ -const formWithValues = useForm({ - defaultValues: { - firstName: "", - lastName: "", - }, -}); +const Example1 = () => { + const form = useForm({ + defaultValues: { + firstName: "", + lastName: "", + }, + }); -const values = formWithValues.getValues(); - -type test = Expect< - Equal ->; + return ( +
{ + type test = Expect< + Equal + >; + })} + > + + + + ); +}; /** * 2. When you don't pass a default value, the return type of getValues is @@ -27,8 +36,17 @@ type test = Expect< * Investigate why this is, and what type FieldValues is. */ -const formWithoutValues = useForm(); - -const values2 = formWithoutValues.getValues(); +const Example2 = () => { + const form = useForm({}); -type test2 = Expect>; + return ( +
{ + type test = Expect>; + })} + > + + + + ); +}; From 21047abaf0350f00e673e2d361f6624e3f030e25 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 21 Aug 2023 12:56:04 +0100 Subject: [PATCH 056/105] Changed to P/S --- ...ner.tsx => 73-react-hook-form.problem.tsx} | 2 +- .../73-react-hook-form.solution.tsx | 39 +++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) rename src/09-external-libraries/{73-react-hook-form.explainer.tsx => 73-react-hook-form.problem.tsx} (97%) create mode 100644 src/09-external-libraries/73-react-hook-form.solution.tsx diff --git a/src/09-external-libraries/73-react-hook-form.explainer.tsx b/src/09-external-libraries/73-react-hook-form.problem.tsx similarity index 97% rename from src/09-external-libraries/73-react-hook-form.explainer.tsx rename to src/09-external-libraries/73-react-hook-form.problem.tsx index 1c6e0e9..f19e579 100644 --- a/src/09-external-libraries/73-react-hook-form.explainer.tsx +++ b/src/09-external-libraries/73-react-hook-form.problem.tsx @@ -37,7 +37,7 @@ const Example1 = () => { */ const Example2 = () => { - const form = useForm({}); + const form = useForm(); return (
{ + const form = useForm({ + values: { + firstName: "", + lastName: "", + }, + }); + + return ( + { + type test = Expect< + Equal + >; + })} + > + + + + ); +}; + +const Example2 = () => { + const form = useForm(); + + return ( +
{ + type test = Expect>; + })} + > + + + + ); +}; From 676b6303dbdfb9d5b3641df1324bb5d1cfccbed2 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 21 Aug 2023 13:11:19 +0100 Subject: [PATCH 057/105] WIP --- .../73-react-hook-form.problem.tsx | 27 ++++++++++++ .../73-react-hook-form.solution.tsx | 42 ++++++++++++++++++- 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/src/09-external-libraries/73-react-hook-form.problem.tsx b/src/09-external-libraries/73-react-hook-form.problem.tsx index f19e579..94153a7 100644 --- a/src/09-external-libraries/73-react-hook-form.problem.tsx +++ b/src/09-external-libraries/73-react-hook-form.problem.tsx @@ -50,3 +50,30 @@ const Example2 = () => { ); }; + +/** + * 3. If we don't pass default values, how do we get + * react-hook-form to understand what type our fields are? + */ + +type FormValues = { + firstName: string; + lastName: string; +}; + +const Example3 = () => { + const form = useForm(); + + return ( +
{ + type test = Expect>; + })} + > + + + {/* @ts-expect-error */} + + + ); +}; diff --git a/src/09-external-libraries/73-react-hook-form.solution.tsx b/src/09-external-libraries/73-react-hook-form.solution.tsx index 7e84656..db01003 100644 --- a/src/09-external-libraries/73-react-hook-form.solution.tsx +++ b/src/09-external-libraries/73-react-hook-form.solution.tsx @@ -1,9 +1,15 @@ import { FieldValues, useForm } from "react-hook-form"; import { Equal, Expect } from "../helpers/type-utils"; +/** + * 1. When you provide default values to useForm, the return type of getValues + * gets inferred as the shape of those values. + * + * Investigate why this is, and what TFieldValues is being used for. + */ const Example1 = () => { const form = useForm({ - values: { + defaultValues: { firstName: "", lastName: "", }, @@ -23,6 +29,13 @@ const Example1 = () => { ); }; +/** + * 2. When you don't pass a default value, the return type of getValues is + * inferred as FieldValues. + * + * Investigate why this is, and what type FieldValues is. + */ + const Example2 = () => { const form = useForm(); @@ -37,3 +50,30 @@ const Example2 = () => { ); }; + +/** + * 3. If we don't pass default values, how do we get + * react-hook-form to understand what type our fields are? + */ + +type FormValues = { + firstName: string; + lastName: string; +}; + +const Example3 = () => { + const form = useForm(); + + return ( +
{ + type test = Expect>; + })} + > + + + {/* @ts-expect-error */} + + + ); +}; From d9ee27ef4c968d52c69198b218952a63ed5f92ac Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 21 Aug 2023 13:22:04 +0100 Subject: [PATCH 058/105] Added another hint to 74 --- .../74-react-hook-form-wrapper.problem.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/09-external-libraries/74-react-hook-form-wrapper.problem.tsx b/src/09-external-libraries/74-react-hook-form-wrapper.problem.tsx index f24d09a..cc6591b 100644 --- a/src/09-external-libraries/74-react-hook-form-wrapper.problem.tsx +++ b/src/09-external-libraries/74-react-hook-form-wrapper.problem.tsx @@ -7,6 +7,10 @@ import { Equal, Expect, Extends } from "../helpers/type-utils"; * We want to change the API slightly so that only certain methods are * exposed. We also want to make sure that defaultValues is ALWAYS * required. + * + * A clue: you'll need this line of code: + * + * defaultValues as DefaultValues */ const useCustomForm = (defaultValues: any) => { const form = useForm({ From a61f352a02860680e42dd01ebd3b48fc13891b15 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 21 Aug 2023 13:29:58 +0100 Subject: [PATCH 059/105] Changed 74 solution --- ...74-react-hook-form-wrapper.solution.1.tsx} | 9 --- .../74-react-hook-form-wrapper.solution.2.tsx | 61 +++++++++++++++++++ 2 files changed, 61 insertions(+), 9 deletions(-) rename src/09-external-libraries/{74-react-hook-form-wrapper.solution.tsx => 74-react-hook-form-wrapper.solution.1.tsx} (77%) create mode 100644 src/09-external-libraries/74-react-hook-form-wrapper.solution.2.tsx diff --git a/src/09-external-libraries/74-react-hook-form-wrapper.solution.tsx b/src/09-external-libraries/74-react-hook-form-wrapper.solution.1.tsx similarity index 77% rename from src/09-external-libraries/74-react-hook-form-wrapper.solution.tsx rename to src/09-external-libraries/74-react-hook-form-wrapper.solution.1.tsx index 0053076..6857b57 100644 --- a/src/09-external-libraries/74-react-hook-form-wrapper.solution.tsx +++ b/src/09-external-libraries/74-react-hook-form-wrapper.solution.1.tsx @@ -1,17 +1,8 @@ import { DefaultValues, FieldValues, useForm } from "react-hook-form"; import { Equal, Expect, Extends } from "../helpers/type-utils"; -/** - * We add TValues as a generic to our hook, and use it to type the defaultValues. - * - * We constrain it to FieldValues so that it's assignable to useForm's defaultValues. - */ const useCustomForm = (defaultValues: TValues) => { const form = useForm({ - /** - * There's a strange papercut here where we have to cast defaultValues as - * DefaultValues to get it to work. - */ defaultValues: defaultValues as DefaultValues, }); diff --git a/src/09-external-libraries/74-react-hook-form-wrapper.solution.2.tsx b/src/09-external-libraries/74-react-hook-form-wrapper.solution.2.tsx new file mode 100644 index 0000000..663ed01 --- /dev/null +++ b/src/09-external-libraries/74-react-hook-form-wrapper.solution.2.tsx @@ -0,0 +1,61 @@ +import { + DefaultValues, + FieldValues, + UseFormGetValues, + UseFormHandleSubmit, + UseFormRegister, + useForm, +} from "react-hook-form"; +import { Equal, Expect, Extends } from "../helpers/type-utils"; + +const useCustomForm = ( + defaultValues: TValues, +): { + register: UseFormRegister; + handleSubmit: UseFormHandleSubmit; + getValues: UseFormGetValues; +} => { + const form = useForm({ + defaultValues: defaultValues as DefaultValues, + }); + + return { + register: form.register, + handleSubmit: form.handleSubmit, + getValues: form.getValues, + }; +}; + +// ---- TESTS ---- + +// @ts-expect-error defaultValues is required +useCustomForm(); + +useCustomForm( + // @ts-expect-error defaultValues must be an object + 2, +); + +const customForm = useCustomForm({ + firstName: "", + lastName: "", +}); + +customForm.handleSubmit((values) => { + type test = Expect< + // Expect that inside handleSubmit, it's inferred as + // { firstName: string; lastName: string } + Extends< + { + firstName: string; + lastName: string; + }, + typeof values + > + >; +}); + +// Expect that only the methods we want are exposed +type test = Expect< + Equal +>; From 46043fb3190b071ac7fc66387dbcb467a6f52a7b Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 21 Aug 2023 13:49:34 +0100 Subject: [PATCH 060/105] Fixed 75 solution --- src/09-external-libraries/75-react-select.solution.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/09-external-libraries/75-react-select.solution.tsx b/src/09-external-libraries/75-react-select.solution.tsx index 42cfd96..1af56c8 100644 --- a/src/09-external-libraries/75-react-select.solution.tsx +++ b/src/09-external-libraries/75-react-select.solution.tsx @@ -1,11 +1,8 @@ import ReactSelect, { GroupBase, Props } from "react-select"; import { Equal, Expect } from "../helpers/type-utils"; -/** - * You need to mimic the exact type of the Props type exported by react-select. - */ export const Select = < - Option, + Option = unknown, IsMulti extends boolean = false, Group extends GroupBase