From f47d08b928be0e762bc130ec93e790ad5eff9fab Mon Sep 17 00:00:00 2001 From: Shu Uesugi Date: Tue, 19 Nov 2019 21:40:33 -0800 Subject: [PATCH 1/2] Up to attempt 1 --- package.json | 2 +- snippets/snippets/generics/bfka.ts | 12 +++++++ snippets/snippets/generics/qqic.ts | 13 ++++++++ snippets/snippets/generics/ystu.ts | 13 ++++++++ src/lib/snippets.ts | 41 +++++++++++++++++++++++ src/pages/generics.tsx | 53 ++++++++++++++++++++++++++++++ 6 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 snippets/snippets/generics/bfka.ts create mode 100644 snippets/snippets/generics/qqic.ts create mode 100644 snippets/snippets/generics/ystu.ts diff --git a/package.json b/package.json index 295fe46..b47a3b0 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "eslint": "eslint --ext .js,.ts,.tsx .", "eslint:fix": "eslint --ext .js,.ts,.tsx --fix .", "svgr": "svgr --ext tsx --no-svgo --no-dimensions -d .", - "snippets": "runSnippet snippets/bin/generateSnippetsBundle.ts", + "snippets": "yarn runSnippet snippets/bin/generateSnippetsBundle.ts", "runSnippet": "ts-node --project tsconfig.snippets.json" }, "devDependencies": { diff --git a/snippets/snippets/generics/bfka.ts b/snippets/snippets/generics/bfka.ts new file mode 100644 index 0000000..0f0eadf --- /dev/null +++ b/snippets/snippets/generics/bfka.ts @@ -0,0 +1,12 @@ +// We want to modify createState() to support +// creating two different states: + +// One that only allows numbers, and… +const numState = createState() +numState.setState(1) +console.log(numState.getState()) // 1 + +// The other that only allows strings. +const strState = createState() +strState.setState('foo') +console.log(strState.getState()) // foo diff --git a/snippets/snippets/generics/qqic.ts b/snippets/snippets/generics/qqic.ts new file mode 100644 index 0000000..77433b6 --- /dev/null +++ b/snippets/snippets/generics/qqic.ts @@ -0,0 +1,13 @@ +// Doesn't work because the created state… +const numAndStrState = createState() + +// Supports both numbers… +numAndStrState.setState(1) +console.log(numAndStrState.getState()) + +// And strings. +numAndStrState.setState('foo') +console.log(numAndStrState.getState()) + +// This is NOT what we want. We want to create +// a number-only state, and a string-only state. diff --git a/snippets/snippets/generics/ystu.ts b/snippets/snippets/generics/ystu.ts new file mode 100644 index 0000000..0f56219 --- /dev/null +++ b/snippets/snippets/generics/ystu.ts @@ -0,0 +1,13 @@ +function createState() { + let state: number | string + + function getState() { + return state + } + + function setState(x: number | string) { + state = x + } + + return { getState, setState } +} diff --git a/src/lib/snippets.ts b/src/lib/snippets.ts index c44392c..e7dc262 100644 --- a/src/lib/snippets.ts +++ b/src/lib/snippets.ts @@ -1,3 +1,16 @@ +export const bfka = `// We want to modify createState() to support +// creating two different states: + +// One that only allows numbers, and… +const numState = createState() +numState.setState(1) +console.log(numState.getState()) // 1 + +// The other that only allows strings. +const strState = createState() +strState.setState('foo') +console.log(strState.getState()) // foo` + export const cbeq = `const { getState, setState } = createState() setState(1) @@ -78,6 +91,20 @@ const { getState, setState } = createState() setState('foo') console.log(getState())` +export const qqic = `// Doesn't work because the created state… +const numAndStrState = createState() + +// Supports both numbers… +numAndStrState.setState(1) +console.log(numAndStrState.getState()) + +// And strings. +numAndStrState.setState('foo') +console.log(numAndStrState.getState()) + +// This is NOT what we want. We want to create +// a number-only state, and a string-only state.` + export const stkh = `const { getState, setState } = createState() // What happens if we use a string instead? @@ -111,6 +138,20 @@ export const xeax = `const { getState, setState } = createState() setState('foo') console.log(getState())` +export const ystu = `function createState() { + let state: number | string + + function getState() { + return state + } + + function setState(x: number | string) { + state = x + } + + return { getState, setState } +}` + export const zhql = `function createState() { let state: number diff --git a/src/pages/generics.tsx b/src/pages/generics.tsx index 812c3a4..0ec0ae9 100644 --- a/src/pages/generics.tsx +++ b/src/pages/generics.tsx @@ -176,6 +176,59 @@ const Page = () => ( ) }, + { + title: <>Challenge: Two different states, + content: ( + <> +

Now that we got the basics down, here’s a challenge question:

+

+ + Can we modify createState() such that, it can + create two different states: + {' '} + one that only allows numbers, and the other that only allows + strings? +

+

Here’s what I mean:

+ +

+ Our first createState() created number-only states, + and our second createState() created string-only + states. However, it couldn’t create both number-only states and + string-only states. +

+

+ How can we modify createState() to achieve our goal? +

+ + ) + }, + { + title: <>Attempt 1: Does this work?, + content: ( + <> +

Here’s the first attempt. Does this work?

+ + (lineNumber === 7 && tokenNumber > 4 && tokenNumber < 10) || + (lineNumber === 1 && tokenNumber > 4 && tokenNumber < 10) + } + /> +

+ This does NOT work. If you use this, you’ll end + up creating a state that allows both numbers and strings, which is + not what we want. +

+ +

+ Instead, we want createState() to support creating + two different states: one that allows only numbers, and the other + that allows only strings. +

+ + ) + }, underConstructionCard ]} /> From 6d71d61f9eadba161f88730a8943f2ffe6a33f53 Mon Sep 17 00:00:00 2001 From: Shu Uesugi Date: Tue, 19 Nov 2019 22:19:33 -0800 Subject: [PATCH 2/2] Finish up to step 6 --- snippets/snippets/generics/brze.ts | 13 ++++++ snippets/snippets/generics/defo.ts | 21 +++++++++ snippets/snippets/generics/gjgg.ts | 6 +++ snippets/snippets/generics/hkgv.ts | 6 +++ snippets/snippets/generics/jdhu.ts | 2 + snippets/snippets/generics/rebo.ts | 6 +++ src/components/Caption.tsx | 1 + src/lib/snippets.ts | 60 +++++++++++++++++++++++++ src/pages/generics.tsx | 72 ++++++++++++++++++++++++++++++ 9 files changed, 187 insertions(+) create mode 100644 snippets/snippets/generics/brze.ts create mode 100644 snippets/snippets/generics/defo.ts create mode 100644 snippets/snippets/generics/gjgg.ts create mode 100644 snippets/snippets/generics/hkgv.ts create mode 100644 snippets/snippets/generics/jdhu.ts create mode 100644 snippets/snippets/generics/rebo.ts diff --git a/snippets/snippets/generics/brze.ts b/snippets/snippets/generics/brze.ts new file mode 100644 index 0000000..3260657 --- /dev/null +++ b/snippets/snippets/generics/brze.ts @@ -0,0 +1,13 @@ +function createState() { + let state: S + + function getState() { + return state + } + + function setState(x: S) { + state = x + } + + return { getState, setState } +} diff --git a/snippets/snippets/generics/defo.ts b/snippets/snippets/generics/defo.ts new file mode 100644 index 0000000..233a224 --- /dev/null +++ b/snippets/snippets/generics/defo.ts @@ -0,0 +1,21 @@ +function createState() { + let state: S + + function getState() { + return state + } + + function setState(x: S) { + state = x + } + + return { getState, setState } +} + +const numState = createState() +numState.setState(1) +console.log(numState.getState()) + +const strState = createState() +strState.setState('foo') +console.log(strState.getState()) diff --git a/snippets/snippets/generics/gjgg.ts b/snippets/snippets/generics/gjgg.ts new file mode 100644 index 0000000..d50e50e --- /dev/null +++ b/snippets/snippets/generics/gjgg.ts @@ -0,0 +1,6 @@ +// Creates a number-only state +const numState = createState() +numState.setState(1) +console.log(numState.getState()) + +// numState.setState('foo') will fail! diff --git a/snippets/snippets/generics/hkgv.ts b/snippets/snippets/generics/hkgv.ts new file mode 100644 index 0000000..47e5ee2 --- /dev/null +++ b/snippets/snippets/generics/hkgv.ts @@ -0,0 +1,6 @@ +// Creates a string-only state +const strState = createState() +strState.setState('foo') +console.log(strState.getState()) + +// strState.setState(1) will fail! diff --git a/snippets/snippets/generics/jdhu.ts b/snippets/snippets/generics/jdhu.ts new file mode 100644 index 0000000..c6164ce --- /dev/null +++ b/snippets/snippets/generics/jdhu.ts @@ -0,0 +1,2 @@ +// It sets S as number +createState() diff --git a/snippets/snippets/generics/rebo.ts b/snippets/snippets/generics/rebo.ts new file mode 100644 index 0000000..7634715 --- /dev/null +++ b/snippets/snippets/generics/rebo.ts @@ -0,0 +1,6 @@ +// In the function definition of createState() +let state: S // <- number + +function setState(x: S /* <- number */) { + state = x +} diff --git a/src/components/Caption.tsx b/src/components/Caption.tsx index a1fd9ab..5288c79 100644 --- a/src/components/Caption.tsx +++ b/src/components/Caption.tsx @@ -13,6 +13,7 @@ const Caption = ({ children }: { children: React.ReactNode }) => { padding-bottom: ${spaces(0.5)}; max-width: 18rem; margin: 0 auto; + text-align: center; ` ]} > diff --git a/src/lib/snippets.ts b/src/lib/snippets.ts index e7dc262..5f9fa9e 100644 --- a/src/lib/snippets.ts +++ b/src/lib/snippets.ts @@ -11,6 +11,20 @@ const strState = createState() strState.setState('foo') console.log(strState.getState()) // foo` +export const brze = `function createState() { + let state: S + + function getState() { + return state + } + + function setState(x: S) { + state = x + } + + return { getState, setState } +}` + export const cbeq = `const { getState, setState } = createState() setState(1) @@ -33,6 +47,35 @@ export const cupt = `function createState() { return { getState, setState } }` +export const defo = `function createState() { + let state: S + + function getState() { + return state + } + + function setState(x: S) { + state = x + } + + return { getState, setState } +} + +const numState = createState() +numState.setState(1) +console.log(numState.getState()) + +const strState = createState() +strState.setState('foo') +console.log(strState.getState())` + +export const gjgg = `// Creates a number-only state +const numState = createState() +numState.setState(1) +console.log(numState.getState()) + +// numState.setState('foo') will fail!` + export const gkgi = `function createState() { // Change to string let state: string @@ -49,6 +92,16 @@ export const gkgi = `function createState() { return { getState, setState } }` +export const hkgv = `// Creates a string-only state +const strState = createState() +strState.setState('foo') +console.log(strState.getState()) + +// strState.setState(1) will fail!` + +export const jdhu = `// It sets S as number +createState()` + export const kiyi = `// Confused by generics code like this? function getProperty( obj: T, @@ -105,6 +158,13 @@ console.log(numAndStrState.getState()) // This is NOT what we want. We want to create // a number-only state, and a string-only state.` +export const rebo = `// In the function definition of createState() +let state: S // <- number + +function setState(x: S /* <- number */) { + state = x +}` + export const stkh = `const { getState, setState } = createState() // What happens if we use a string instead? diff --git a/src/pages/generics.tsx b/src/pages/generics.tsx index 0ec0ae9..9ebf172 100644 --- a/src/pages/generics.tsx +++ b/src/pages/generics.tsx @@ -229,6 +229,78 @@ const Page = () => ( ) }, + { + title: <>Attempt 2: Use generics, + content: ( + <> +

+ This is where generics come in. Take a look + below: +

+ + (lineNumber === 7 && tokenNumber > 4 && tokenNumber < 8) || + (lineNumber === 1 && tokenNumber > 4 && tokenNumber < 6) || + (lineNumber === 0 && tokenNumber > 1 && tokenNumber < 5) + } + /> +

+ createState() is now defined as{' '} + createState<S>(). You can think of{' '} + <S> as another argument that you have to pass + in when you call the function. But instead of passing a value, you + pass a type to it. It’s a type argument. +

+

+ For example, you can pass the type number as{' '} + S when you call createState(): +

+ +

+ Then, inside the function definition of createState() + , S will be come number: +

+ +

+ Because state will be number and{' '} + setState will only take number, it + creates a number-only state. +

+ + lineNumber === 1 && tokenNumber > 5 && tokenNumber < 7 + } + /> +

+ And to create a string-only state, you can pass{' '} + number as S when you call{' '} + createState(): +

+ + lineNumber === 1 && tokenNumber > 5 && tokenNumber < 7 + } + /> +

+ That’s it! And we call createState<S>() a + “generic function” because it’s flexible—you have a choice to make + it number-only or string-only. You know it’s a generic function if + it takes a type parameter when you call it. +

+ + createState<S>() is a generic function + + } + /> + + ) + }, underConstructionCard ]} />