From 372f24cba11dc0c308a9309610ef2ee8f6e0b95f Mon Sep 17 00:00:00 2001 From: Shu Uesugi Date: Thu, 21 Nov 2019 17:16:59 -0800 Subject: [PATCH 01/12] Up to slide 11 --- snippets/snippets/generics/gozc.ts | 8 +++ snippets/snippets/generics/jejx.ts | 7 +++ snippets/snippets/generics/nbvo.ts | 4 ++ snippets/snippets/generics/qgxj.ts | 5 ++ snippets/snippets/generics/rxdm.ts | 16 ++++++ snippets/snippets/generics/ugeb.ts | 16 ++++++ src/lib/snippets.ts | 62 +++++++++++++++++++++ src/pages/generics.tsx | 89 ++++++++++++++++++++++++++++++ 8 files changed, 207 insertions(+) create mode 100644 snippets/snippets/generics/gozc.ts create mode 100644 snippets/snippets/generics/jejx.ts create mode 100644 snippets/snippets/generics/nbvo.ts create mode 100644 snippets/snippets/generics/qgxj.ts create mode 100644 snippets/snippets/generics/rxdm.ts create mode 100644 snippets/snippets/generics/ugeb.ts diff --git a/snippets/snippets/generics/gozc.ts b/snippets/snippets/generics/gozc.ts new file mode 100644 index 0000000..a07dd6d --- /dev/null +++ b/snippets/snippets/generics/gozc.ts @@ -0,0 +1,8 @@ +// Creates a (number, string) pair +const { getPair, setPair } = makePair< + number, + string +>() + +// Must pass (number, string) +setPair(1, 'hello') diff --git a/snippets/snippets/generics/jejx.ts b/snippets/snippets/generics/jejx.ts new file mode 100644 index 0000000..1ef9636 --- /dev/null +++ b/snippets/snippets/generics/jejx.ts @@ -0,0 +1,7 @@ +const { getPair, setPair } = makePair() + +setPair(1, 2) +console.log(getPair()) + +setPair(3, 4) +console.log(getPair()) diff --git a/snippets/snippets/generics/nbvo.ts b/snippets/snippets/generics/nbvo.ts new file mode 100644 index 0000000..025f921 --- /dev/null +++ b/snippets/snippets/generics/nbvo.ts @@ -0,0 +1,4 @@ +function makePair< + F extends number | string = number, + S extends number | string = number +>() diff --git a/snippets/snippets/generics/qgxj.ts b/snippets/snippets/generics/qgxj.ts new file mode 100644 index 0000000..159f301 --- /dev/null +++ b/snippets/snippets/generics/qgxj.ts @@ -0,0 +1,5 @@ +// makeState() has 1 type parameter +function makeState() + +// makePair() has 2 type parameters +function makePair() diff --git a/snippets/snippets/generics/rxdm.ts b/snippets/snippets/generics/rxdm.ts new file mode 100644 index 0000000..2ac56af --- /dev/null +++ b/snippets/snippets/generics/rxdm.ts @@ -0,0 +1,16 @@ +function makePair() { + let pair: { first: F; second: S } + + function getPair() { + return pair + } + + function setPair(x: F, y: S) { + pair = { + first: x, + second: y + } + } + + return { getPair, setPair } +} diff --git a/snippets/snippets/generics/ugeb.ts b/snippets/snippets/generics/ugeb.ts new file mode 100644 index 0000000..7f8eccf --- /dev/null +++ b/snippets/snippets/generics/ugeb.ts @@ -0,0 +1,16 @@ +function makePair() { + let pair: { first: number; second: number } + + function getPair() { + return pair + } + + function setPair(x: number, y: number) { + pair = { + first: x, + second: y + } + } + + return { getPair, setPair } +} diff --git a/src/lib/snippets.ts b/src/lib/snippets.ts index 3eb9dc6..24e8831 100644 --- a/src/lib/snippets.ts +++ b/src/lib/snippets.ts @@ -119,6 +119,15 @@ export const gkgi = `function makeState() { return { getState, setState } }` +export const gozc = `// Creates a (number, string) pair +const { getPair, setPair } = makePair< + number, + string +>() + +// Must pass (number, string) +setPair(1, 'hello')` + export const gzwe = `// Don’t need to use const numState = makeState() @@ -135,6 +144,14 @@ console.log(strState.getState()) export const jdhu = `// It sets S as number makeState()` +export const jejx = `const { getPair, setPair } = makePair() + +setPair(1, 2) +console.log(getPair()) + +setPair(3, 4) +console.log(getPair())` + export const kbld = `// Limits the type of T function genericFunc() @@ -156,6 +173,11 @@ console.log(boolState.getState())` export const mngc = `function makeState()` +export const nbvo = `function makePair< + F extends number | string = number, + S extends number | string = number +>()` + export const nnyl = `function makeState() { let state: number @@ -225,6 +247,12 @@ function regularFunc(x = 2) // x will be 2 inside the function regularFunc()` +export const qgxj = `// makeState() has 1 type parameter +function makeState() + +// makePair() has 2 type parameters +function makePair()` + export const qini = `// Specify x to be number function regularFunc(x: number) @@ -254,6 +282,23 @@ function setState(x: S /* <- number */) { state = x }` +export const rxdm = `function makePair() { + let pair: { first: F; second: S } + + function getPair() { + return pair + } + + function setPair(x: F, y: S) { + pair = { + first: x, + second: y + } + } + + return { getPair, setPair } +}` + export const stkh = `const { getState, setState } = makeState() // What happens if we use a string instead? @@ -287,6 +332,23 @@ console.log(getState()) setState(2) console.log(getState())` +export const ugeb = `function makePair() { + let pair: { first: number; second: number } + + function getPair() { + return pair + } + + function setPair(x: number, y: number) { + pair = { + first: x, + second: y + } + } + + return { getPair, setPair } +}` + export const wpru = `// Declare a regular function function regularFunc(x: any) { // You can use x here diff --git a/src/pages/generics.tsx b/src/pages/generics.tsx index b7e46a4..cc2d06b 100644 --- a/src/pages/generics.tsx +++ b/src/pages/generics.tsx @@ -528,6 +528,95 @@ const Page = () => ( ) }, + { + title: ( + <> + Let’s talk about makePair + + ), + content: ( + <> +

+ Let’s take a look at the new function called{' '} + makePair(). It’s similar to makeState(), + but instead of storing a single value, this one stores a pair of + values as {`{ first: ?, second: ? }`}. Right now, it + only supports numbers. +

+ +

+ Let’s try it out!{' '} + + What gets printed out to the console when you run the following + code? + {' '} + Try to guess first, and then{' '} + + press the button + + . +

+ + {`{ first: 1, second: 2 }`} +
+ {`{ first: 3, second: 4 }`} + + } + /> +

+ Now, just like makeState(), let’s turn{' '} + makePair() into a generic function. +

+ + ) + }, + { + title: ( + <> + Generic makePair + + ), + content: ( + <> +

+ Here’s a generic version of makePair. +

+
    + + It takes two type parameters F and{' '} + S (for “F”irst and “S”econd). + + + The type of first will be F. + + + The type of second will be S. + +
+ +

+ Here’s an example usage. By calling makePair with{' '} + <number, string>, it forces first{' '} + to be number and second to be{' '} + string. +

+ +

+ So, you can create a generic function that takes{' '} + multiple type parameters. +

+ +

+ Of course, you can also use the extends keyword or + default types like before: +

+ + + ) + }, underConstructionCard ]} /> From 2299bd0bfa284af22e97a2cd1dd2800e177b310c Mon Sep 17 00:00:00 2001 From: Shu Uesugi Date: Thu, 21 Nov 2019 17:48:02 -0800 Subject: [PATCH 02/12] Continue with step 11 --- snippets/snippets/generics/bwyu.ts | 5 +++++ snippets/snippets/generics/kiyi.ts | 5 ----- snippets/snippets/generics/xekh.ts | 19 ++++++++++++++++++ src/lib/snippets.ts | 32 ++++++++++++++++++++++++------ src/pages/generics.tsx | 13 +++++++++++- 5 files changed, 62 insertions(+), 12 deletions(-) create mode 100644 snippets/snippets/generics/bwyu.ts delete mode 100644 snippets/snippets/generics/kiyi.ts create mode 100644 snippets/snippets/generics/xekh.ts diff --git a/snippets/snippets/generics/bwyu.ts b/snippets/snippets/generics/bwyu.ts new file mode 100644 index 0000000..14b8679 --- /dev/null +++ b/snippets/snippets/generics/bwyu.ts @@ -0,0 +1,5 @@ +// Confused by generics code like this? +function makePair< + F extends number | string, + S extends { foo: F } +>() diff --git a/snippets/snippets/generics/kiyi.ts b/snippets/snippets/generics/kiyi.ts deleted file mode 100644 index 572326f..0000000 --- a/snippets/snippets/generics/kiyi.ts +++ /dev/null @@ -1,5 +0,0 @@ -// Confused by generics code like this? -function getProperty( - obj: T, - key: K -) diff --git a/snippets/snippets/generics/xekh.ts b/snippets/snippets/generics/xekh.ts new file mode 100644 index 0000000..ad2ec47 --- /dev/null +++ b/snippets/snippets/generics/xekh.ts @@ -0,0 +1,19 @@ +// You can make type S to be related to type F. +// Whatever type you specify for F determines +// the possible types of S. +function makePair< + F extends number | string, + S extends { foo: F } +>() + +// Example usage: We’ll pass in number for F, so +// for S, we must pass in a type that extends +// or is equal to { foo: number }. +const { getPair, setPair } = makePair< + number, + { foo: number } +>() + +// Now, setPair takes number and +// an object containing { foo: number } pair +setPair(1, { foo: 5 }) diff --git a/src/lib/snippets.ts b/src/lib/snippets.ts index 24e8831..6165fc4 100644 --- a/src/lib/snippets.ts +++ b/src/lib/snippets.ts @@ -33,6 +33,12 @@ export const brze = `function makeState() { return { getState, setState } }` +export const bwyu = `// Confused by generics code like this? +function makePair< + F extends number | string, + S extends { foo: F } +>()` + export const cbeq = `const { getState, setState } = makeState() setState(1) @@ -160,12 +166,6 @@ genericFunc() // Error genericFunc()` -export const kiyi = `// Confused by generics code like this? -function getProperty( - obj: T, - key: K -)` - export const llvc = `// Creates a boolean-only state const boolState = makeState() boolState.setState(true) @@ -362,6 +362,26 @@ export const xeax = `const { getState, setState } = makeState() setState('foo') console.log(getState())` +export const xekh = `// You can make type S to be related to type F. +// Whatever type you specify for F determines +// the possible types of S. +function makePair< + F extends number | string, + S extends { foo: F } +>() + +// Example usage: We’ll pass in number for F, so +// for S, we must pass in a type that extends +// or is equal to { foo: number }. +const { getPair, setPair } = makePair< + number, + { foo: number } +>() + +// Now, setPair takes number and +// an object containing { foo: number } pair +setPair(1, { foo: 5 })` + export const xfwf = `// Can we make it so that, is the // default type paramter of makeState()? diff --git a/src/pages/generics.tsx b/src/pages/generics.tsx index cc2d06b..11f0893 100644 --- a/src/pages/generics.tsx +++ b/src/pages/generics.tsx @@ -18,7 +18,7 @@ const Page = () => ( title: <>TypeScript Generics Too Hard?, content: ( <> - +

If you’re (1) new to TypeScript, (2) new to{' '} generics, and (3) struggling to @@ -614,9 +614,20 @@ const Page = () => ( default types like before:

+

+ You can even make the second type (S) to be related + to the first type (F). In the following (slightly + complicated) case, whatever type you specify for F{' '} + determines the possible types of S. +

+ ) }, + { + title: <>Generic interfaces, + content: <> + }, underConstructionCard ]} /> From ec35e75d278b02086a669d56a95492c4af649551 Mon Sep 17 00:00:00 2001 From: Shu Uesugi Date: Thu, 21 Nov 2019 18:25:15 -0800 Subject: [PATCH 03/12] Tweak generics --- snippets/snippets/generics/bwyu.ts | 2 +- snippets/snippets/generics/xekh.ts | 25 +++++++++++-------------- src/lib/snippets.ts | 27 ++++++++++++--------------- src/pages/generics.tsx | 4 +--- 4 files changed, 25 insertions(+), 33 deletions(-) diff --git a/snippets/snippets/generics/bwyu.ts b/snippets/snippets/generics/bwyu.ts index 14b8679..b02171e 100644 --- a/snippets/snippets/generics/bwyu.ts +++ b/snippets/snippets/generics/bwyu.ts @@ -1,5 +1,5 @@ // Confused by generics code like this? function makePair< F extends number | string, - S extends { foo: F } + S extends boolean | F >() diff --git a/snippets/snippets/generics/xekh.ts b/snippets/snippets/generics/xekh.ts index ad2ec47..fae0ae1 100644 --- a/snippets/snippets/generics/xekh.ts +++ b/snippets/snippets/generics/xekh.ts @@ -1,19 +1,16 @@ -// You can make type S to be related to type F. -// Whatever type you specify for F determines -// the possible types of S. +// The second parameter S must be either +// boolean or whatever was specified for F function makePair< F extends number | string, - S extends { foo: F } + S extends boolean | F >() -// Example usage: We’ll pass in number for F, so -// for S, we must pass in a type that extends -// or is equal to { foo: number }. -const { getPair, setPair } = makePair< - number, - { foo: number } ->() +// These will work +makePair() +makePair() +makePair() +makePair() -// Now, setPair takes number and -// an object containing { foo: number } pair -setPair(1, { foo: 5 }) +// This will fail because the second +// parameter must be boolean | boolean +makePair() diff --git a/src/lib/snippets.ts b/src/lib/snippets.ts index 6165fc4..e5c3bcd 100644 --- a/src/lib/snippets.ts +++ b/src/lib/snippets.ts @@ -36,7 +36,7 @@ export const brze = `function makeState() { export const bwyu = `// Confused by generics code like this? function makePair< F extends number | string, - S extends { foo: F } + S extends boolean | F >()` export const cbeq = `const { getState, setState } = makeState() @@ -362,25 +362,22 @@ export const xeax = `const { getState, setState } = makeState() setState('foo') console.log(getState())` -export const xekh = `// You can make type S to be related to type F. -// Whatever type you specify for F determines -// the possible types of S. +export const xekh = `// The second parameter S must be either +// boolean or whatever was specified for F function makePair< F extends number | string, - S extends { foo: F } + S extends boolean | F >() -// Example usage: We’ll pass in number for F, so -// for S, we must pass in a type that extends -// or is equal to { foo: number }. -const { getPair, setPair } = makePair< - number, - { foo: number } ->() +// These will work +makePair() +makePair() +makePair() +makePair() -// Now, setPair takes number and -// an object containing { foo: number } pair -setPair(1, { foo: 5 })` +// This will fail because the second +// parameter must be boolean | boolean +makePair()` export const xfwf = `// Can we make it so that, is the // default type paramter of makeState()? diff --git a/src/pages/generics.tsx b/src/pages/generics.tsx index 11f0893..99fba8a 100644 --- a/src/pages/generics.tsx +++ b/src/pages/generics.tsx @@ -616,9 +616,7 @@ const Page = () => (

You can even make the second type (S) to be related - to the first type (F). In the following (slightly - complicated) case, whatever type you specify for F{' '} - determines the possible types of S. + to the first type (F). Here’s an example:

From 8f617ad9da940fa3a0b29f58e8c7ac69c8e653cd Mon Sep 17 00:00:00 2001 From: Shu Uesugi Date: Thu, 21 Nov 2019 21:17:51 -0800 Subject: [PATCH 04/12] Finish writing --- README.md | 16 ++++- snippets/snippets/generics/lldl.ts | 13 ++++ snippets/snippets/generics/mrub.ts | 5 ++ snippets/snippets/generics/qgea.ts | 6 ++ src/components/ContentTags/A.tsx | 21 ++++++ src/components/ContentTags/index.tsx | 1 + src/components/Footer.tsx | 32 +++++++++ src/components/Page.tsx | 4 +- src/components/TwitterLink.tsx | 5 +- src/lib/snippets.ts | 27 +++++++ src/lib/theme/spaces.ts | 4 +- src/pages/generics.tsx | 104 +++++++++++++++++++++++++-- src/pages/index.tsx | 2 +- 13 files changed, 226 insertions(+), 14 deletions(-) create mode 100644 snippets/snippets/generics/lldl.ts create mode 100644 snippets/snippets/generics/mrub.ts create mode 100644 snippets/snippets/generics/qgea.ts create mode 100644 src/components/ContentTags/A.tsx create mode 100644 src/components/Footer.tsx diff --git a/README.md b/README.md index 3366e38..f118e2e 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,19 @@ -# TypeScript for Beginner Programmers +# [TypeScript for Beginner Programmers](https://ts.chibicode.com) + +### This is the repository for the TypeScript tutorial website called **[TypeScript for Beginner Programmers](https://ycombinator.chibicode.com/)**. + +[![](public/images/og-index.png)](https://ts.chibicode.com) ## License & Credits - For emojis, I’m using [Twemoji](https://github.com/twitter/twemoji) by Twitter (CC-BY 4.0 license). - The text for this course is licensed under [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/). -- Everything else is licensed under the [MIT](LICENSE-non-text.txt) license. \ No newline at end of file +- Everything else is licensed under the [MIT](LICENSE-non-text.txt) license. + +## Author + +**Shu Uesugi** + +- Twitter: [@chibicode](https://twitter.com/chibicode) +- [Website](https://chibicode.com) +- Email: [shu@chibicode.com](mailto:shu@chibicode.com) \ No newline at end of file diff --git a/snippets/snippets/generics/lldl.ts b/snippets/snippets/generics/lldl.ts new file mode 100644 index 0000000..362382c --- /dev/null +++ b/snippets/snippets/generics/lldl.ts @@ -0,0 +1,13 @@ +// Extract into a generic interface +// to make it reusable +interface Pair { + first: A + second: B +} + +function makePair() { + // Usage: Pass F for A and S for B + let pair: Pair + + // ... +} diff --git a/snippets/snippets/generics/mrub.ts b/snippets/snippets/generics/mrub.ts new file mode 100644 index 0000000..50d403b --- /dev/null +++ b/snippets/snippets/generics/mrub.ts @@ -0,0 +1,5 @@ +function makePair() { + let pair: { first: F; second: S } + + // ... +} diff --git a/snippets/snippets/generics/qgea.ts b/snippets/snippets/generics/qgea.ts new file mode 100644 index 0000000..b53124c --- /dev/null +++ b/snippets/snippets/generics/qgea.ts @@ -0,0 +1,6 @@ +// Extract into a generic type alias. It’s +// basically identical to using an interface +type Pair = { + first: A + second: B +} diff --git a/src/components/ContentTags/A.tsx b/src/components/ContentTags/A.tsx new file mode 100644 index 0000000..e443239 --- /dev/null +++ b/src/components/ContentTags/A.tsx @@ -0,0 +1,21 @@ +/** @jsx jsx */ +import { css, jsx } from '@emotion/core' +import useTheme from 'src/hooks/useTheme' + +const A = (props: JSX.IntrinsicElements['a']) => { + const { colors } = useTheme() + return ( + + ) +} + +export default A diff --git a/src/components/ContentTags/index.tsx b/src/components/ContentTags/index.tsx index 1aa7480..01b1846 100644 --- a/src/components/ContentTags/index.tsx +++ b/src/components/ContentTags/index.tsx @@ -3,4 +3,5 @@ export { default as H3 } from 'src/components/ContentTags/H3' export { default as Code } from 'src/components/ContentTags/Code' export { default as Highlight } from 'src/components/ContentTags/Highlight' export { default as Hr } from 'src/components/ContentTags/Hr' +export { default as A } from 'src/components/ContentTags/A' export { Ul, Ol, UlLi, OlLi } from 'src/components/ContentTags/List' diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx new file mode 100644 index 0000000..b0efa88 --- /dev/null +++ b/src/components/Footer.tsx @@ -0,0 +1,32 @@ +/** @jsx jsx */ +import { css, jsx } from '@emotion/core' +import Container from 'src/components/Container' +import useTheme from 'src/hooks/useTheme' +import { A } from 'src/components/ContentTags' + +const Footer = () => { + const { fontSizes, ns, spaces, colors } = useTheme() + + return ( + + The source code for this site is{' '} + + available on GitHub + + . + + ) +} + +export default Footer diff --git a/src/components/Page.tsx b/src/components/Page.tsx index 5e5875e..da4879e 100644 --- a/src/components/Page.tsx +++ b/src/components/Page.tsx @@ -4,6 +4,7 @@ import GlobalStyles from 'src/components/GlobalStyles' import Head from 'next/head' import Container from 'src/components/Container' import Header from 'src/components/Header' +import Footer from 'src/components/Footer' import useTheme from 'src/hooks/useTheme' const Page = ({ @@ -54,11 +55,12 @@ const Page = ({
{children} +