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
+
+ .
+
+
+ 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:
+ >
+ )
+ }
},
- underConstructionCard
+ {
+ title: <>That’s all you need to know!>,
+ content: (
+ <>
+
+ Thanks for reading! Hope I made generics less scary. If you’d like
+ me to write about some other topic on TypeScript, or if you have
+ feedback, please let me know on{' '}
+
+ Twitter at @chibicode
+
+ .
+
+ >
+ ),
+ footer: {
+ content: (
+ <>
+
+ About the author: I’m Shu Uesugi, a software
+ engineer. The most recent TypeScript project I worked on is an{' '}
+ interactive computer science course called{' '}
+
+ “Y Combinator for Non-programmers.”
+
+ .
+
-
+
)
}
From 871596c20a7112532b07fe99d27339d397ba40e0 Mon Sep 17 00:00:00 2001
From: Shu Uesugi
Date: Fri, 22 Nov 2019 00:44:46 -0800
Subject: [PATCH 09/12] Fix up to step 2
---
src/components/ContentTags/Code.tsx | 8 +++++--
src/pages/generics.tsx | 33 +++++++++++++++++------------
2 files changed, 26 insertions(+), 15 deletions(-)
diff --git a/src/components/ContentTags/Code.tsx b/src/components/ContentTags/Code.tsx
index f50a1c7..3f3e345 100644
--- a/src/components/ContentTags/Code.tsx
+++ b/src/components/ContentTags/Code.tsx
@@ -1,8 +1,12 @@
/** @jsx jsx */
import { css, jsx } from '@emotion/core'
import useTheme from 'src/hooks/useTheme'
+import { allColors } from 'src/lib/theme/colors'
-const Code = (props: JSX.IntrinsicElements['code']) => {
+const Code = ({
+ color,
+ ...props
+}: JSX.IntrinsicElements['code'] & { color?: keyof typeof allColors }) => {
const { colors } = useTheme()
return (
{
css`
font-size: 0.9em;
word-break: break-word;
- background: ${colors('lightPink2')};
+ background: ${color ? colors(color) : colors('lightPink2')};
`
]}
/>
diff --git a/src/pages/generics.tsx b/src/pages/generics.tsx
index ec11a9c..c42b320 100644
--- a/src/pages/generics.tsx
+++ b/src/pages/generics.tsx
@@ -57,11 +57,11 @@ const Page = () => (
Note: If you already understand generics, you
won’t find anything new in this tutorial. However,{' '}
- you might know someone (maybe your colleague or your Twitter
- follower) who’s struggling with generics
+ you might know someone (maybe one of your Twitter followers)
+ who’s struggling with generics
- . If so, I’d appreciate it if you could share this article with
- them. You can{' '}
+ . If you do, I’d appreciate it if you could share this article
+ with them. You can{' '}
(
content: (
<>
- Note: If you’ve used React, you might realize
- that it’s kind of like the useState() hook.
+ Note: If you’ve used React, you might have
+ realized that makeState() is
+ similar to the useState(){' '}
+ hook.
>
)
@@ -320,27 +322,32 @@ const Page = () => (
<>
You might be wondering: Why did we name the
- type parameter as “S”?
+ type parameter as “S”?
Answer: It could actually be any name, but
usually people use the first letter of a word that describes
what the type is representing. In this case, I chose “
- S” because it’s describing the type of a{' '}
- “S”tate. The following names are also common:
+ S” because it’s describing the
+ type of a “S”tate. The following names are also
+ common:
- T (for “T”ype)
+ T (for “T”
+ ype)
- E (for “E”lement)
+ E (for “E”
+ lement)
- K (for “K”ey)
+ K (for “K”
+ ey)
- V (for “V”alue)
+ V (for “V”
+ alue)
>
From a33924becf6fb8a2fe7758e879b2057d85acffa6 Mon Sep 17 00:00:00 2001
From: Shu Uesugi
Date: Fri, 22 Nov 2019 00:59:01 -0800
Subject: [PATCH 10/12] Finish slide 6
---
snippets/snippets/generics/qqic.ts | 4 +--
src/lib/snippets.ts | 4 +--
src/pages/generics.tsx | 51 ++++++++++++++----------------
3 files changed, 28 insertions(+), 31 deletions(-)
diff --git a/snippets/snippets/generics/qqic.ts b/snippets/snippets/generics/qqic.ts
index 148d91f..362bb1c 100644
--- a/snippets/snippets/generics/qqic.ts
+++ b/snippets/snippets/generics/qqic.ts
@@ -1,7 +1,7 @@
// Doesn't work because the created state…
const numAndStrState = makeState()
-// Supports both numbers…
+// Allows both numbers…
numAndStrState.setState(1)
console.log(numAndStrState.getState())
@@ -10,4 +10,4 @@ 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.
+// a number-only state and a string-only state.
diff --git a/src/lib/snippets.ts b/src/lib/snippets.ts
index ca236ab..386d50f 100644
--- a/src/lib/snippets.ts
+++ b/src/lib/snippets.ts
@@ -291,7 +291,7 @@ regularFunc('foo')`
export const qqic = `// Doesn't work because the created state…
const numAndStrState = makeState()
-// Supports both numbers…
+// Allows both numbers…
numAndStrState.setState(1)
console.log(numAndStrState.getState())
@@ -300,7 +300,7 @@ 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.`
+// a number-only state and a string-only state.`
export const rebo = `// In the function definition of makeState()
let state: S // <- number
diff --git a/src/pages/generics.tsx b/src/pages/generics.tsx
index c42b320..d15439e 100644
--- a/src/pages/generics.tsx
+++ b/src/pages/generics.tsx
@@ -29,10 +29,9 @@ const Page = () => (
Back then, I was studying the Java programming language in
college. Generics were a relatively new feature for Java at the
time. I was a beginner programmer then, and{' '}
- generics felt very difficult. So I gave up on actually
- understanding generics and used them without knowing what I was
- doing. I never really understood generics until I had to use them
- a lot for my job.
+ generics felt very difficult. So I gave up on
+ understanding generics at the time. I had to re-learn generics
+ when I got a full time job.
(
/>
Similarly, if you feel that TypeScript generics are too difficult,
- this tutorial is for you! I’ll try to help you actually understand
+ this tutorial is for you! I’ll help you actually understand
generics.
>
@@ -173,8 +172,8 @@ const Page = () => (
}
/>
- To fix this, we can change the types from number to{' '}
- string:
+ To fix this, we can change the type of state and{' '}
+ x from number to string:
(
title: <>Challenge: Two different states>,
content: (
<>
-
Now that we got the basics down, here’s a challenge question:
+
Now that we got the basics down, here’s a challenge for you:
+ Question:{' '}
Can we modify makeState() such that, it can create
two different states:
@@ -209,10 +209,10 @@ const Page = () => (
Here’s what I mean:
- 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.
+ Earlier, 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 makeState() to achieve our goal?
@@ -233,16 +233,13 @@ const Page = () => (
}
/>
- 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.
+ This does NOT work. You’ll end up creating a
+ state that allows both numbers and strings, which is not what we
+ want. Instead, we want makeState() 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.
-
>
)
},
@@ -276,7 +273,7 @@ const Page = () => (
Then, inside the function definition of makeState(),{' '}
- S will be come number:
+ S will become number:
@@ -291,8 +288,8 @@ const Page = () => (
}
/>
- And to create a string-only state, you can pass{' '}
- number as S when you call{' '}
+ On the other hand, to create a string-only state, you can pass{' '}
+ string as S when you call{' '}
makeState():
(
}
/>
- 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.
+ Note: We call makeState<S>() a{' '}
+ “generic function” because it’s literally
+ generic—you have a choice to make it number-only or string-only.
+ And you know it’s a generic function if it takes a type parameter.
+ It resulted in an error, which is what we want! We have
+ successfully prevented makeState() from creating
+ non-number or non-string states.
+
As you just saw, you can specify what’s allowed for the type
parameter(s) of a generic function.
@@ -446,8 +451,8 @@ const Page = () => (
Can we make it so that <number> is the
default type parameter of makeState()?
{' '}
- We want to make it so that, if the type is missing, it’s set as{' '}
- number by default.
+ We want to make it so that, if S is unspecified, it’s
+ set as number by default.
@@ -487,7 +492,7 @@ const Page = () => (
The difference is that{' '}
regular function parameters deal with values, but generics deal
- with types.
+ with type parameters.
@@ -543,9 +548,12 @@ const Page = () => (
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.
+ but instead of storing a single value,{' '}
+
+ this one stores a pair of values as{' '}
+ {`{ first: ?, second: ? }`}
+
+ . Right now, it only supports numbers.
@@ -571,7 +579,7 @@ const Page = () => (
}
/>
- Now, just like makeState(), let’s turn{' '}
+ Now, just as we did for makeState(), let’s turn{' '}
makePair() into a generic function.
- So, you can create a generic function that takes{' '}
+ To summarize, you can create a generic function that takes{' '}
multiple type parameters.
@@ -651,12 +660,16 @@ const Page = () => (
Let’s first extract the type of pair into a{' '}
- generic interface. I used A and{' '}
+ generic interface. I’ll use A and{' '}
B as type parameter names to distinguish them from
- the type parameters of makePair(). We can then use
- this interface to declare the type for pair.
+ the type parameters of makePair().
+
+ We can then use this interface to declare the type for{' '}
+ pair.
+
+
By extracting into a generic interface (an interface that takes
type parameters), we can reuse it in other places if necessary.
@@ -670,9 +683,8 @@ const Page = () => (
- So, you can create generic interfaces and type aliases, just as
- you can create generic functions. You can also create generic
- classes, but we won’t cover that here for brevity.
+ To summarize, you can create generic interfaces and type aliases,
+ just as you can create generic functions.
## 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/).
+- The text for this website 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.
## Author
diff --git a/snippets/snippets/generics/mroc.ts b/snippets/snippets/generics/mroc.ts
new file mode 100644
index 0000000..aa20fe5
--- /dev/null
+++ b/snippets/snippets/generics/mroc.ts
@@ -0,0 +1,11 @@
+class State {
+ state: S
+
+ getState() {
+ return this.state
+ }
+
+ setState(x: S) {
+ this.state = x
+ }
+}
diff --git a/snippets/snippets/generics/zdbq.ts b/snippets/snippets/generics/zdbq.ts
new file mode 100644
index 0000000..48bf819
--- /dev/null
+++ b/snippets/snippets/generics/zdbq.ts
@@ -0,0 +1,7 @@
+// Pass a type parameter on initialization
+const numState = new State()
+
+numState.setState(1)
+
+// Prints 1
+console.log(numState.getState())
diff --git a/src/lib/snippets.ts b/src/lib/snippets.ts
index d656854..0562790 100644
--- a/src/lib/snippets.ts
+++ b/src/lib/snippets.ts
@@ -187,6 +187,18 @@ console.log(boolState.getState())`
export const mngc = `function makeState()`
+export const mroc = `class State {
+ state: S
+
+ getState() {
+ return this.state
+ }
+
+ setState(x: S) {
+ this.state = x
+ }
+}`
+
export const mrub = `function makePair() {
let pair: { first: F; second: S }
@@ -430,6 +442,14 @@ export const ystu = `function makeState() {
return { getState, setState }
}`
+export const zdbq = `// Pass a type parameter on initialization
+const numState = new State()
+
+numState.setState(1)
+
+// Prints 1
+console.log(numState.getState())`
+
export const zhql = `function makeState() {
let state: number
diff --git a/src/pages/generics.tsx b/src/pages/generics.tsx
index c3d5e82..00ad8c6 100644
--- a/src/pages/generics.tsx
+++ b/src/pages/generics.tsx
@@ -707,15 +707,72 @@ const Page = () => (
)
}
},
+ {
+ title: <>Generic classes>,
+ content: (
+ <>
+
+
+ The last thing we’ll cover is generic classes.
+ {' '}
+ First, let’s revisit the code for makeState(). This
+ is the generic version that doesn’t use extends or
+ default type parameters.
+
+
+ Let’s revisit makeState()
+ >
+ }
+ />
+
+ We can turn makeState() into a generic class called{' '}
+ State like below. It looks similar to{' '}
+ makeState(), right?
+
+
+
+ To use this, you just need to pass a type parameter on
+ initialization.
+
+
+
+ To summarize, generic classes are just like generic functions.
+ Generic functions take a type parameter when we call them, but
+ generic classes take a type parameter when we instantiate them.
+
+ >
+ ),
+ footer: {
+ content: (
+ <>
+
+ Note: You need to set{' '}
+
+ "strictPropertyInitialization": false
+ {' '}
+ on TypeScript config (
+ tsconfig.json) to get the
+ above code to compile.
+
+ >
+ )
+ }
+ },
{
title: <>That’s all you need to know!>,
content: (
<>
- Thanks for reading! Hope I made generics less scary. If you’d like
- me to write about some other topics on TypeScript, or if you have
- feedback, please let me know on{' '}
+ Thanks for reading! That’s all you need to know about generics in
+ TypeScript. Hope I made generics less scary to you.
+
+
+ If you’d like me to write about some other topics on TypeScript,
+ or if you have feedback, please let me know on{' '}
Twitter at @chibicode
diff --git a/tsconfig.snippets.json b/tsconfig.snippets.json
index c6ddd24..48b56c4 100644
--- a/tsconfig.snippets.json
+++ b/tsconfig.snippets.json
@@ -4,7 +4,8 @@
"target": "es2017",
"module": "commonjs",
"lib": ["es2017"],
- "isolatedModules": false
+ "isolatedModules": false,
+ "strictPropertyInitialization": false
},
"include": ["./snippets"]
}