From 22185e410e33ff30df52c4965598173ce992a656 Mon Sep 17 00:00:00 2001 From: Shu Uesugi Date: Wed, 20 Nov 2019 10:43:50 -0800 Subject: [PATCH 1/2] Add sitemap --- public/sitemap.xml | 13 +++++++++++++ src/pages/generics.tsx | 4 ++++ 2 files changed, 17 insertions(+) create mode 100644 public/sitemap.xml diff --git a/public/sitemap.xml b/public/sitemap.xml new file mode 100644 index 0000000..29ca9be --- /dev/null +++ b/public/sitemap.xml @@ -0,0 +1,13 @@ + + + + https://ts.chibicode.com + + + https://ts.chibicode.com/generics + + \ No newline at end of file diff --git a/src/pages/generics.tsx b/src/pages/generics.tsx index 9ebf172..34b5266 100644 --- a/src/pages/generics.tsx +++ b/src/pages/generics.tsx @@ -301,6 +301,10 @@ const Page = () => ( ) }, + { + title: <>But you can create a boolean state!, + content: <> + }, underConstructionCard ]} /> From 9efa7cb23acaf254aac656e53b69dc4a827d3ba7 Mon Sep 17 00:00:00 2001 From: Shu Uesugi Date: Wed, 20 Nov 2019 12:20:35 -0800 Subject: [PATCH 2/2] Up to step 7 of generics article --- .prettierrc | 2 +- snippets/snippets/generics/bfka.ts | 6 +- snippets/snippets/generics/brze.ts | 2 +- snippets/snippets/generics/cbeq.ts | 2 +- snippets/snippets/generics/cupt.ts | 2 +- snippets/snippets/generics/defo.ts | 6 +- snippets/snippets/generics/dngl.ts | 18 +++++ snippets/snippets/generics/gjgg.ts | 2 +- snippets/snippets/generics/gkgi.ts | 2 +- snippets/snippets/generics/hkgv.ts | 2 +- snippets/snippets/generics/jdhu.ts | 2 +- snippets/snippets/generics/llvc.ts | 4 + snippets/snippets/generics/mngc.ts | 1 + snippets/snippets/generics/nnyl.ts | 2 +- snippets/snippets/generics/osaa.ts | 4 +- snippets/snippets/generics/qqic.ts | 2 +- snippets/snippets/generics/rebo.ts | 2 +- snippets/snippets/generics/stkh.ts | 2 +- snippets/snippets/generics/udpv.ts | 4 +- snippets/snippets/generics/xeax.ts | 2 +- snippets/snippets/generics/ystu.ts | 2 +- snippets/snippets/generics/zhql.ts | 4 +- src/components/Emoji/ChickEgg.tsx | 26 ++++++ src/components/Emoji/index.tsx | 4 +- src/lib/snippets.ts | 76 ++++++++++++------ src/pages/generics.tsx | 122 +++++++++++++++++++++++------ 26 files changed, 228 insertions(+), 75 deletions(-) create mode 100644 snippets/snippets/generics/dngl.ts create mode 100644 snippets/snippets/generics/llvc.ts create mode 100644 snippets/snippets/generics/mngc.ts create mode 100644 src/components/Emoji/ChickEgg.tsx diff --git a/.prettierrc b/.prettierrc index 351537b..7ce38e9 100644 --- a/.prettierrc +++ b/.prettierrc @@ -5,7 +5,7 @@ { "files": "snippets/snippets/**/*.ts", "options": { - "printWidth": 49 + "printWidth": 48 } } ] diff --git a/snippets/snippets/generics/bfka.ts b/snippets/snippets/generics/bfka.ts index 0f0eadf..e45f3ae 100644 --- a/snippets/snippets/generics/bfka.ts +++ b/snippets/snippets/generics/bfka.ts @@ -1,12 +1,12 @@ -// We want to modify createState() to support +// We want to modify makeState() to support // creating two different states: // One that only allows numbers, and… -const numState = createState() +const numState = makeState() numState.setState(1) console.log(numState.getState()) // 1 // The other that only allows strings. -const strState = createState() +const strState = makeState() strState.setState('foo') console.log(strState.getState()) // foo diff --git a/snippets/snippets/generics/brze.ts b/snippets/snippets/generics/brze.ts index 3260657..32bb4c1 100644 --- a/snippets/snippets/generics/brze.ts +++ b/snippets/snippets/generics/brze.ts @@ -1,4 +1,4 @@ -function createState() { +function makeState() { let state: S function getState() { diff --git a/snippets/snippets/generics/cbeq.ts b/snippets/snippets/generics/cbeq.ts index 9e8f346..bcc4f92 100644 --- a/snippets/snippets/generics/cbeq.ts +++ b/snippets/snippets/generics/cbeq.ts @@ -1,4 +1,4 @@ -const { getState, setState } = createState() +const { getState, setState } = makeState() setState(1) console.log(getState()) diff --git a/snippets/snippets/generics/cupt.ts b/snippets/snippets/generics/cupt.ts index 29911e8..9507081 100644 --- a/snippets/snippets/generics/cupt.ts +++ b/snippets/snippets/generics/cupt.ts @@ -1,4 +1,4 @@ -function createState() { +function makeState() { let state: number function getState() { diff --git a/snippets/snippets/generics/defo.ts b/snippets/snippets/generics/defo.ts index 233a224..625fd70 100644 --- a/snippets/snippets/generics/defo.ts +++ b/snippets/snippets/generics/defo.ts @@ -1,4 +1,4 @@ -function createState() { +function makeState() { let state: S function getState() { @@ -12,10 +12,10 @@ function createState() { return { getState, setState } } -const numState = createState() +const numState = makeState() numState.setState(1) console.log(numState.getState()) -const strState = createState() +const strState = makeState() strState.setState('foo') console.log(strState.getState()) diff --git a/snippets/snippets/generics/dngl.ts b/snippets/snippets/generics/dngl.ts new file mode 100644 index 0000000..7d08b45 --- /dev/null +++ b/snippets/snippets/generics/dngl.ts @@ -0,0 +1,18 @@ +function makeState< + S extends number | string +>() { + let state: S + + function getState() { + return state + } + + function setState(x: S) { + state = x + } + + return { getState, setState } +} + +// What happens if we now pass boolean to S? +const boolState = makeState() diff --git a/snippets/snippets/generics/gjgg.ts b/snippets/snippets/generics/gjgg.ts index d50e50e..32aff4f 100644 --- a/snippets/snippets/generics/gjgg.ts +++ b/snippets/snippets/generics/gjgg.ts @@ -1,5 +1,5 @@ // Creates a number-only state -const numState = createState() +const numState = makeState() numState.setState(1) console.log(numState.getState()) diff --git a/snippets/snippets/generics/gkgi.ts b/snippets/snippets/generics/gkgi.ts index 35a8142..f5eebb5 100644 --- a/snippets/snippets/generics/gkgi.ts +++ b/snippets/snippets/generics/gkgi.ts @@ -1,4 +1,4 @@ -function createState() { +function makeState() { // Change to string let state: string diff --git a/snippets/snippets/generics/hkgv.ts b/snippets/snippets/generics/hkgv.ts index 47e5ee2..9f067f1 100644 --- a/snippets/snippets/generics/hkgv.ts +++ b/snippets/snippets/generics/hkgv.ts @@ -1,5 +1,5 @@ // Creates a string-only state -const strState = createState() +const strState = makeState() strState.setState('foo') console.log(strState.getState()) diff --git a/snippets/snippets/generics/jdhu.ts b/snippets/snippets/generics/jdhu.ts index c6164ce..0353966 100644 --- a/snippets/snippets/generics/jdhu.ts +++ b/snippets/snippets/generics/jdhu.ts @@ -1,2 +1,2 @@ // It sets S as number -createState() +makeState() diff --git a/snippets/snippets/generics/llvc.ts b/snippets/snippets/generics/llvc.ts new file mode 100644 index 0000000..11b8d44 --- /dev/null +++ b/snippets/snippets/generics/llvc.ts @@ -0,0 +1,4 @@ +// Creates a boolean-only state +const boolState = makeState() +boolState.setState(true) +console.log(boolState.getState()) diff --git a/snippets/snippets/generics/mngc.ts b/snippets/snippets/generics/mngc.ts new file mode 100644 index 0000000..e141fb5 --- /dev/null +++ b/snippets/snippets/generics/mngc.ts @@ -0,0 +1 @@ +function makeState() diff --git a/snippets/snippets/generics/nnyl.ts b/snippets/snippets/generics/nnyl.ts index d5ecab4..11fa6b7 100644 --- a/snippets/snippets/generics/nnyl.ts +++ b/snippets/snippets/generics/nnyl.ts @@ -1,4 +1,4 @@ -function createState() { +function makeState() { let state: number function getState() { diff --git a/snippets/snippets/generics/osaa.ts b/snippets/snippets/generics/osaa.ts index 0a64aad..08cec96 100644 --- a/snippets/snippets/generics/osaa.ts +++ b/snippets/snippets/generics/osaa.ts @@ -1,4 +1,4 @@ -function createState() { +function makeState() { // Change to string let state: string @@ -14,7 +14,7 @@ function createState() { return { getState, setState } } -const { getState, setState } = createState() +const { getState, setState } = makeState() setState('foo') console.log(getState()) diff --git a/snippets/snippets/generics/qqic.ts b/snippets/snippets/generics/qqic.ts index 77433b6..148d91f 100644 --- a/snippets/snippets/generics/qqic.ts +++ b/snippets/snippets/generics/qqic.ts @@ -1,5 +1,5 @@ // Doesn't work because the created state… -const numAndStrState = createState() +const numAndStrState = makeState() // Supports both numbers… numAndStrState.setState(1) diff --git a/snippets/snippets/generics/rebo.ts b/snippets/snippets/generics/rebo.ts index 7634715..4cda5c0 100644 --- a/snippets/snippets/generics/rebo.ts +++ b/snippets/snippets/generics/rebo.ts @@ -1,4 +1,4 @@ -// In the function definition of createState() +// In the function definition of makeState() let state: S // <- number function setState(x: S /* <- number */) { diff --git a/snippets/snippets/generics/stkh.ts b/snippets/snippets/generics/stkh.ts index 1ee3c09..6925591 100644 --- a/snippets/snippets/generics/stkh.ts +++ b/snippets/snippets/generics/stkh.ts @@ -1,4 +1,4 @@ -const { getState, setState } = createState() +const { getState, setState } = makeState() // What happens if we use a string instead? setState('foo') diff --git a/snippets/snippets/generics/udpv.ts b/snippets/snippets/generics/udpv.ts index 5dfdf0c..ad83dcd 100644 --- a/snippets/snippets/generics/udpv.ts +++ b/snippets/snippets/generics/udpv.ts @@ -1,4 +1,4 @@ -function createState() { +function makeState() { let state: number function getState() { @@ -12,7 +12,7 @@ function createState() { return { getState, setState } } -const { getState, setState } = createState() +const { getState, setState } = makeState() setState(1) console.log(getState()) diff --git a/snippets/snippets/generics/xeax.ts b/snippets/snippets/generics/xeax.ts index 5632156..93bb86e 100644 --- a/snippets/snippets/generics/xeax.ts +++ b/snippets/snippets/generics/xeax.ts @@ -1,4 +1,4 @@ -const { getState, setState } = createState() +const { getState, setState } = makeState() setState('foo') console.log(getState()) diff --git a/snippets/snippets/generics/ystu.ts b/snippets/snippets/generics/ystu.ts index 0f56219..d0df0d5 100644 --- a/snippets/snippets/generics/ystu.ts +++ b/snippets/snippets/generics/ystu.ts @@ -1,4 +1,4 @@ -function createState() { +function makeState() { let state: number | string function getState() { diff --git a/snippets/snippets/generics/zhql.ts b/snippets/snippets/generics/zhql.ts index 6a6a2a2..f1a53cb 100644 --- a/snippets/snippets/generics/zhql.ts +++ b/snippets/snippets/generics/zhql.ts @@ -1,4 +1,4 @@ -function createState() { +function makeState() { let state: number function getState() { @@ -12,7 +12,7 @@ function createState() { return { getState, setState } } -const { getState, setState } = createState() +const { getState, setState } = makeState() setState('foo') console.log(getState()) diff --git a/src/components/Emoji/ChickEgg.tsx b/src/components/Emoji/ChickEgg.tsx new file mode 100644 index 0000000..663f501 --- /dev/null +++ b/src/components/Emoji/ChickEgg.tsx @@ -0,0 +1,26 @@ +import React from 'react' + +const SvgChickEgg = (props: React.SVGProps) => ( + + + + + + + + +) + +export default SvgChickEgg diff --git a/src/components/Emoji/index.tsx b/src/components/Emoji/index.tsx index 22a37e5..6c09a58 100644 --- a/src/components/Emoji/index.tsx +++ b/src/components/Emoji/index.tsx @@ -4,12 +4,14 @@ import Bird from 'src/components/Emoji/Bird' import CryingCat from 'src/components/Emoji/CryingCat' import Question from 'src/components/Emoji/Question' import Run from 'src/components/Emoji/Run' +import ChickEgg from 'src/components/Emoji/ChickEgg' export const emojiToComponent = { bird: Bird, cryingCat: CryingCat, question: Question, - run: Run + run: Run, + chickEgg: ChickEgg } const Emoji = ({ diff --git a/src/lib/snippets.ts b/src/lib/snippets.ts index 5f9fa9e..5e10266 100644 --- a/src/lib/snippets.ts +++ b/src/lib/snippets.ts @@ -1,17 +1,17 @@ -export const bfka = `// We want to modify createState() to support +export const bfka = `// We want to modify makeState() to support // creating two different states: // One that only allows numbers, and… -const numState = createState() +const numState = makeState() numState.setState(1) console.log(numState.getState()) // 1 // The other that only allows strings. -const strState = createState() +const strState = makeState() strState.setState('foo') console.log(strState.getState()) // foo` -export const brze = `function createState() { +export const brze = `function makeState() { let state: S function getState() { @@ -25,7 +25,7 @@ export const brze = `function createState() { return { getState, setState } }` -export const cbeq = `const { getState, setState } = createState() +export const cbeq = `const { getState, setState } = makeState() setState(1) console.log(getState()) @@ -33,7 +33,7 @@ console.log(getState()) setState(2) console.log(getState())` -export const cupt = `function createState() { +export const cupt = `function makeState() { let state: number function getState() { @@ -47,7 +47,7 @@ export const cupt = `function createState() { return { getState, setState } }` -export const defo = `function createState() { +export const defo = `function makeState() { let state: S function getState() { @@ -61,22 +61,41 @@ export const defo = `function createState() { return { getState, setState } } -const numState = createState() +const numState = makeState() numState.setState(1) console.log(numState.getState()) -const strState = createState() +const strState = makeState() strState.setState('foo') console.log(strState.getState())` +export const dngl = `function makeState< + S extends number | string +>() { + let state: S + + function getState() { + return state + } + + function setState(x: S) { + state = x + } + + return { getState, setState } +} + +// What happens if we now pass boolean to S? +const boolState = makeState()` + export const gjgg = `// Creates a number-only state -const numState = createState() +const numState = makeState() numState.setState(1) console.log(numState.getState()) // numState.setState('foo') will fail!` -export const gkgi = `function createState() { +export const gkgi = `function makeState() { // Change to string let state: string @@ -93,14 +112,14 @@ export const gkgi = `function createState() { }` export const hkgv = `// Creates a string-only state -const strState = createState() +const strState = makeState() strState.setState('foo') console.log(strState.getState()) // strState.setState(1) will fail!` export const jdhu = `// It sets S as number -createState()` +makeState()` export const kiyi = `// Confused by generics code like this? function getProperty( @@ -108,7 +127,14 @@ function getProperty( key: K )` -export const nnyl = `function createState() { +export const llvc = `// Creates a boolean-only state +const boolState = makeState() +boolState.setState(true) +console.log(boolState.getState())` + +export const mngc = `function makeState()` + +export const nnyl = `function makeState() { let state: number function getState() { @@ -123,7 +149,7 @@ export const nnyl = `function createState() { return { getState, setState } }` -export const osaa = `function createState() { +export const osaa = `function makeState() { // Change to string let state: string @@ -139,13 +165,13 @@ export const osaa = `function createState() { return { getState, setState } } -const { getState, setState } = createState() +const { getState, setState } = makeState() setState('foo') console.log(getState())` export const qqic = `// Doesn't work because the created state… -const numAndStrState = createState() +const numAndStrState = makeState() // Supports both numbers… numAndStrState.setState(1) @@ -158,20 +184,20 @@ 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() +export const rebo = `// In the function definition of makeState() let state: S // <- number function setState(x: S /* <- number */) { state = x }` -export const stkh = `const { getState, setState } = createState() +export const stkh = `const { getState, setState } = makeState() // What happens if we use a string instead? setState('foo') console.log(getState())` -export const udpv = `function createState() { +export const udpv = `function makeState() { let state: number function getState() { @@ -185,7 +211,7 @@ export const udpv = `function createState() { return { getState, setState } } -const { getState, setState } = createState() +const { getState, setState } = makeState() setState(1) console.log(getState()) @@ -193,12 +219,12 @@ console.log(getState()) setState(2) console.log(getState())` -export const xeax = `const { getState, setState } = createState() +export const xeax = `const { getState, setState } = makeState() setState('foo') console.log(getState())` -export const ystu = `function createState() { +export const ystu = `function makeState() { let state: number | string function getState() { @@ -212,7 +238,7 @@ export const ystu = `function createState() { return { getState, setState } }` -export const zhql = `function createState() { +export const zhql = `function makeState() { let state: number function getState() { @@ -226,7 +252,7 @@ export const zhql = `function createState() { return { getState, setState } } -const { getState, setState } = createState() +const { getState, setState } = makeState() setState('foo') console.log(getState())` diff --git a/src/pages/generics.tsx b/src/pages/generics.tsx index 34b5266..d8fdd8c 100644 --- a/src/pages/generics.tsx +++ b/src/pages/generics.tsx @@ -61,18 +61,18 @@ const Page = () => ( { title: ( <> - Let’s talk about createState() + Let’s talk about makeState() ), content: ( <>

- First, I created a function called createState(){' '} - below. We’ll use this function to talk about generics. + First, I created a function called makeState() below. + We’ll use this function to talk about generics.

- When you run createState(), it returns two functions:{' '} + When you run makeState(), it returns two functions:{' '} getState() and setState(). You can use these functions to set and get the variable called{' '} state. @@ -183,8 +183,8 @@ const Page = () => (

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

- Can we modify createState() such that, it can - create two different states: + Can we modify makeState() such that, it can create + two different states: {' '} one that only allows numbers, and the other that only allows strings? @@ -192,13 +192,13 @@ const Page = () => (

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 + Our first makeState() created number-only states, and + our second makeState() 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? + How can we modify makeState() to achieve our goal?

) @@ -222,9 +222,9 @@ const Page = () => (

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

) @@ -246,20 +246,20 @@ const Page = () => ( } />

- createState() is now defined as{' '} - createState<S>(). You can think of{' '} + makeState() is now defined as{' '} + makeState<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(): + S when you call makeState():

- Then, inside the function definition of createState() - , S will be come number: + Then, inside the function definition of makeState(),{' '} + S will be come number:

@@ -276,7 +276,7 @@ const Page = () => (

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

( } />

- That’s it! And we call createState<S>() a + That’s it! And we call makeState<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 + makeState<S>() is a generic function } /> @@ -303,7 +303,83 @@ const Page = () => ( }, { title: <>But you can create a boolean state!, - content: <> + content: ( + <> +

+ But wait a minute: If you pass{' '} + boolean to S, you can create a + boolean-only state. +

+ +

+ Maybe we might NOT want this to be allowed.{' '} + Suppose that don’t want makeState() to be able to + create non-number or non-string states (like boolean + ). How can we make sure that this is the case? +

+ + How can we prevent makeState() from +
+ creating non-number or non-string states? + + } + /> +

+ The solution:{' '} + + When you declare makeState(), you change the type + parameter <S> to{' '} + <S extends number | string> + + . That’s the only change you need to make. +

+ + lineNumber === 0 && tokenNumber > 2 && tokenNumber < 12 + } + /> +

+ By doing this, when you call makeState(), you’d only + be able to pass number, string, or any + other type that extends either number or{' '} + string into S. +

+

+ Let’s see what happens now when you try to pass{' '} + boolean into S.{' '} + + Press below + + . +

+ + lineNumber === 17 && tokenNumber > 5 && tokenNumber < 7 + } + shouldHighlightResult={(lineNumber, tokenNumber) => + lineNumber === 17 && tokenNumber > 5 && tokenNumber < 7 + } + result={ + <> + Type 'boolean' does not satisfy the constraint 'string | + number'. + + } + /> +

It resulted in an error, which is what we want!

+

+ As you just saw, you can specify what’s allowed + for the type parameter(s) of a generic function. +

+ + ) }, underConstructionCard ]}