Skip to content

Commit d054b58

Browse files
committed
Completed 07-types-deep-dive
1 parent 03c68bd commit d054b58

File tree

48 files changed

+259
-80
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+259
-80
lines changed

src/07-types-deep-dive/44-understand-react-namespace-export.explainer.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ type Example = React.ReactNode;
99
/**
1010
* 2a. Most namespaces can't be used as values. So how come
1111
* we can use React as a value here?
12+
*
13+
* HINT - we're adding LOTS of things to React's namespace in
14+
* later exercises, so make sure when you go-to-definition you
15+
* go to its original definition, in @types/react/index.d.ts.
1216
*/
1317
const element = React.createElement("div");
1418
// ^?
Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,31 @@
11
/**
22
* 1. What's the difference between JSX.Element,
33
* React.ReactNode and React.ReactElement?
4+
*
5+
* CMD-click each of them to understand the difference.
46
*/
5-
const Component = () => {
6-
// ^?
7-
return <div>Hello world</div>;
8-
};
97

108
type ClickMe = React.ReactElement;
119
type ClickMeToo = JSX.Element;
1210
type ClickMeThree = React.ReactNode;
1311

1412
/**
15-
* 2. Why does this break?
13+
* 2. What is the return type of this Component?
1614
*/
15+
const Component = () => {
16+
return <div>Hello world</div>;
17+
};
1718

19+
/**
20+
* 3. Fun fact - this might break on your IDE! In
21+
* TypeScript 5.0, this wouldn't work. But in TypeScript
22+
* 5.1, it DOES work.
23+
*
24+
* If it's not working for you, try making your IDE use
25+
* the 'workspace' version of TypeScript.
26+
*
27+
* https://stackoverflow.com/questions/39668731/what-typescript-version-is-visual-studio-code-using-how-to-update-it
28+
*/
1829
const Component2 = (): React.ReactNode => {
1930
return <div></div>;
2031
};
@@ -24,13 +35,19 @@ const Component2 = (): React.ReactNode => {
2435
</>;
2536

2637
/**
27-
* 3. Why does this work?
38+
* 4a. Why does this component NOT error...
2839
*/
29-
3040
const Component3 = (): React.ReactElement => {
3141
return <div></div>;
3242
};
3343

3444
<>
3545
<Component3 />
3646
</>;
47+
48+
/**
49+
* 4b. ...but this one does?
50+
*/
51+
const Component4 = (): React.ReactElement => {
52+
return "hello!";
53+
};
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { ReactNode } from "react";
2+
3+
/**
4+
* In this example we have a Select component. Through some magic, we're
5+
* attempting to strongly type the children of the Select component so
6+
* that you can only pass 'Option' elements to it.
7+
*
8+
* 1. Try to understand the type of OptionType. What's the __brand property
9+
* for?
10+
*
11+
* 2. There's an error happening at <Option /> below. Why is that?
12+
*
13+
* 3. Try changing <Option /> to {Option()}. This appears to work. Why?
14+
* And why is this NOT a good idea?
15+
*
16+
* 4. Is what we're attempting to do even possible?
17+
*/
18+
19+
type OptionType = {
20+
__brand: "OPTION_TYPE";
21+
} & ReactNode;
22+
23+
const Option = () => {
24+
return (<option></option>) as OptionType;
25+
};
26+
27+
const Select = (props: { children: OptionType }) => {
28+
return <select>{props.children}</select>;
29+
};
30+
31+
<Select>
32+
<Option />
33+
</Select>;

src/07-types-deep-dive/46-strongly-typing-children.problem.tsx

Lines changed: 0 additions & 1 deletion
This file was deleted.

src/07-types-deep-dive/47-how-does-react-represent-html.explainer.ts

Lines changed: 0 additions & 3 deletions
This file was deleted.

src/07-types-deep-dive/47-understanding-jsx-intrinsic-elements.explainer.ts

Lines changed: 0 additions & 5 deletions
This file was deleted.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* 1. What is JSX.IntrinsicElements? CMD-click on .IntrinsicElements below
3+
* to go to its definition.
4+
*
5+
* Hint - remember to go to the original definition of JSX.IntrinsicElements
6+
* in @types/react/index.d.ts.
7+
*/
8+
9+
export type Example = JSX.IntrinsicElements;
10+
11+
/**
12+
* 2. What is the structure of JSX.IntrinsicElements? It appears to have the
13+
* HTML attributes as properties, but what are the values?
14+
*
15+
* 3. Let's have some fun. Edit the file to add a new property to
16+
* JSX.IntrinsicElements:
17+
*
18+
* interface IntrinsicElements {
19+
* // ...
20+
* myNewElement: {
21+
* foo: string;
22+
* }
23+
* }
24+
*
25+
* Notice that the error below goes away!
26+
*
27+
* 4. Now change it back, before anyone notices.
28+
*/
29+
30+
<myNewElement foo="123" />;

src/07-types-deep-dive/48-add-new-global-element.problem.tsx

Lines changed: 0 additions & 9 deletions
This file was deleted.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { Equal, Expect } from "../helpers/type-utils";
2+
3+
/**
4+
* It's actually possible to change things in the global namespace
5+
* in TypeScript.
6+
*
7+
* 1. Add a declaration for React.MyInterface to the global React
8+
* namespace below.
9+
*/
10+
11+
declare global {
12+
namespace React {}
13+
}
14+
15+
type test = Expect<Equal<React.MyInterface, { foo: string }>>;
16+
17+
export {};
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { Equal, Expect } from "../helpers/type-utils";
2+
3+
declare global {
4+
namespace React {
5+
// Note that it doesn't need to be exported
6+
interface MySolutionInterface {
7+
foo: string;
8+
}
9+
}
10+
}
11+
12+
type test = Expect<Equal<React.MySolutionInterface, { foo: string }>>;
13+
14+
export {};

src/07-types-deep-dive/49-add-attribute-to-all-elements.problem.tsx

Lines changed: 0 additions & 24 deletions
This file was deleted.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { Equal, Expect } from "../helpers/type-utils";
2+
3+
declare global {
4+
namespace React {
5+
interface MyAwesomeInterface {
6+
foo: string;
7+
}
8+
}
9+
}
10+
11+
/**
12+
* We can use a feature called declaration merging in TypeScript to
13+
* CHANGE interfaces in the global namespace.
14+
*
15+
* WITHOUT changing the code above, change MyAwesomeInterface to add
16+
* a property called 'bar' that is a string.
17+
*
18+
* Clue: you'll need to use declare global, namespace, and interface
19+
* again.
20+
*
21+
* https://www.typescriptlang.org/docs/handbook/declaration-merging.html#merging-interfaces
22+
*/
23+
24+
type test = Expect<
25+
Equal<React.MyAwesomeInterface, { foo: string; bar: string }>
26+
>;
27+
28+
export {};
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { Equal, Expect } from "../helpers/type-utils";
2+
3+
declare global {
4+
namespace React {
5+
interface MyAwesomeSolutionInterface {
6+
foo: string;
7+
}
8+
}
9+
}
10+
11+
/**
12+
* By declaring MyAwesomeSolutionInferface for the second time
13+
* in the same scope, we can add properties to it.
14+
*
15+
* The power of declaration merging!
16+
*/
17+
declare global {
18+
namespace React {
19+
interface MyAwesomeSolutionInterface {
20+
bar: string;
21+
}
22+
}
23+
}
24+
25+
type test = Expect<
26+
Equal<React.MyAwesomeSolutionInterface, { foo: string; bar: string }>
27+
>;
28+
29+
export {};

src/07-types-deep-dive/50-add-attribute-to-audio-elements.problem.tsx

Lines changed: 0 additions & 12 deletions
This file was deleted.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* Let's say we're working with an external library that adds a new
3+
* global element to the DOM. We want to strongly type this element
4+
* so that it can only be used with the correct attributes.
5+
*
6+
* In this case, we're adding a <something /> element to the DOM,
7+
* which takes a required `id` attribute.
8+
*
9+
* Hint - you'll need to declaration merge with an existing
10+
* interface in the React namespace.
11+
*/
12+
13+
<>
14+
<something id="123"></something>
15+
16+
{/* @ts-expect-error */}
17+
<something></something>
18+
19+
{/* @ts-expect-error */}
20+
<something id={123}></something>
21+
</>;

src/07-types-deep-dive/48-add-new-global-element.solution.tsx renamed to src/07-types-deep-dive/50-add-new-global-element.solution.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ declare global {
99
}
1010

1111
<>
12-
<something-solution id="123"></something-solution>
12+
<something-solution id="123" />
1313

1414
{/* @ts-expect-error */}
15-
<something-solution></something-solution>
15+
<something-solution />
1616

1717
{/* @ts-expect-error */}
18-
<something-solution id={123}></something-solution>
18+
<something-solution id={123} />
1919
</>;

src/07-types-deep-dive/51-add-attribute-to-div-elements.problem.tsx

Lines changed: 0 additions & 16 deletions
This file was deleted.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/**
2+
* 1. How does React know which HTML attributes can be passed
3+
* to each HTML element?
4+
*
5+
* On which interfaces/types are they stored?
6+
*/
7+
8+
/**
9+
* 2. Try CMD-clicking on the 'div' below. What information
10+
* does that give you?
11+
*/
12+
<div />;
13+
14+
/**
15+
* 3. Try CMD-clicking on the className prop below. What
16+
* interface does it lead you to?
17+
*/
18+
<div className="foo" />;
19+
20+
/**
21+
* 4. Finally, try CMD-clicking on the 'href' prop below.
22+
* What interface does it lead you to?
23+
*/
24+
<a href="/" />;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/**
2+
* Let's say we wanted to add a new optional attribute to all React
3+
* elements. How would we do that?
4+
*
5+
* 1. Make use of declaration merging in the global scope to add
6+
* a new attribute to all React elements.
7+
*/
8+
9+
<>
10+
<div testId="123" />
11+
<audio testId="123" />
12+
<video testId="123" />
13+
<a testId="123" />
14+
<abbr testId="123" />
15+
<address testId="123" />
16+
</>;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
declare global {
2+
namespace React {
3+
interface HTMLAttributes<T> {
4+
solutionTestId?: string;
5+
}
6+
}
7+
}
8+
9+
<>
10+
<div solutionTestId="123" />
11+
<audio solutionTestId="123" />
12+
<video solutionTestId="123" />
13+
<a solutionTestId="123" />
14+
<abbr solutionTestId="123" />
15+
<address solutionTestId="123" />
16+
</>;

0 commit comments

Comments
 (0)