From 968f231733fa40cf730e6fa66039e970cc16d5e1 Mon Sep 17 00:00:00 2001
From: Shu Uesugi
Date: Fri, 6 Dec 2019 20:04:40 -0800
Subject: [PATCH 1/3] Wordsmith
---
src/pages/todo.tsx | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/pages/todo.tsx b/src/pages/todo.tsx
index 4286142..b3f6544 100644
--- a/src/pages/todo.tsx
+++ b/src/pages/todo.tsx
@@ -858,7 +858,9 @@ const Page = () => (
TypeScript’s types act as lightweight unit tests that run
automatically every time you save (compile) the code.
{' '}
- It helps you write less buggy code with very little overhead.
+ It helps you write less buggy code with very little overhead. (Of
+ course, this analogy is a simplification and you should still
+ write tests in TypeScript!)
This especially useful{' '}
@@ -872,7 +874,9 @@ const Page = () => (
TypeScript reduces bugs when transforming data>}
+ description={
+ <>TypeScript reduces bugs when transforming/passing data>
+ }
/>
From 76defc0b232f2fb9112301bb1f16bdeebaf06b9d Mon Sep 17 00:00:00 2001
From: Shu Uesugi
Date: Fri, 6 Dec 2019 21:59:44 -0800
Subject: [PATCH 2/3] Start mark all as complete
---
snippets/snippets/todo/tdbp.ts | 5 +++
src/lib/snippets.ts | 6 ++++
src/pages/todo.tsx | 63 ++++++++++++++++++++++------------
3 files changed, 52 insertions(+), 22 deletions(-)
create mode 100644 snippets/snippets/todo/tdbp.ts
diff --git a/snippets/snippets/todo/tdbp.ts b/snippets/snippets/todo/tdbp.ts
new file mode 100644
index 0000000..8abd4e1
--- /dev/null
+++ b/snippets/snippets/todo/tdbp.ts
@@ -0,0 +1,5 @@
+// Takes an array of todo items and returns
+// a new array where "done" is all true
+function completeAll(todos) {
+ // ...
+}
diff --git a/src/lib/snippets.ts b/src/lib/snippets.ts
index 36ac729..f6ffd96 100644
--- a/src/lib/snippets.ts
+++ b/src/lib/snippets.ts
@@ -605,6 +605,12 @@ export const reel = `function toggleTodo(todo) {
}
}`
+export const tdbp = `// Takes an array of todo items and returns
+// a new array where "done" is all true
+function completeAll(todos) {
+ // ...
+}`
+
export const tgvw = `const bar: Todo = {
text: '…',
done: true
diff --git a/src/pages/todo.tsx b/src/pages/todo.tsx
index b3f6544..119c387 100644
--- a/src/pages/todo.tsx
+++ b/src/pages/todo.tsx
@@ -859,8 +859,8 @@ const Page = () => (
automatically every time you save (compile) the code.
{' '}
It helps you write less buggy code with very little overhead. (Of
- course, this analogy is a simplification and you should still
- write tests in TypeScript!)
+ course, this analogy is a simplification. You should still write
+ tests in TypeScript!)
This especially useful{' '}
@@ -897,26 +897,45 @@ const Page = () => (
>
)
},
- // {
- // title: <>Mark all as completed>,
- // content: (
- // <>
- //
- // ↓ Try pressing “Mark all as completed”
- // >
- // }
- // defaultData={[
- // { id: 1, text: 'First todo', done: false },
- // { id: 2, text: 'Second todo', done: false }
- // ]}
- // showMarkAllAsCompleted
- // />
- // >
- // )
- // },
+ {
+ title: <>Mark all as completed>,
+ content: (
+ <>
+
+ Some todo apps allow you to{' '}
+ mark all items as completed. On the
+ following todo app,{' '}
+ try pressing “Mark all as completed”:
+
+
+ ↓ Try pressing “Mark all as completed”
+ >
+ }
+ defaultData={[
+ { id: 1, text: 'First todo', done: false },
+ { id: 2, text: 'Second todo', done: false }
+ ]}
+ showMarkAllAsCompleted
+ highlightLineIndexOffset={1}
+ shouldHighlight={tokenIndex => tokenIndex === 15}
+ />
+
+ After pressing “Mark all as completed”, all items will have{' '}
+ done: true.
+
+
+ Let’s implement this functionality using TypeScript. We’ll write a
+ function called completeAll() which takes an array of
+ todo items and returns a new array where done is all{' '}
+ true.
+
+
+ >
+ )
+ },
underConstructionCard
]}
/>
From 30a80dba1b028a9deb85f913191eec9ac9815569 Mon Sep 17 00:00:00 2001
From: Shu Uesugi
Date: Sat, 7 Dec 2019 00:18:22 -0800
Subject: [PATCH 3/3] Continue with mark all as completed
---
snippets/snippets/todo/lgci.ts | 11 +++
snippets/snippets/todo/mnmy.ts | 4 +
snippets/snippets/todo/mwrj.ts | 8 ++
snippets/snippets/todo/szan.ts | 6 ++
src/components/CodeBlock.tsx | 21 ++---
src/lib/snippets.ts | 33 ++++++++
src/pages/todo.tsx | 147 +++++++++++++++++++++++++++++----
7 files changed, 204 insertions(+), 26 deletions(-)
create mode 100644 snippets/snippets/todo/lgci.ts
create mode 100644 snippets/snippets/todo/mnmy.ts
create mode 100644 snippets/snippets/todo/mwrj.ts
create mode 100644 snippets/snippets/todo/szan.ts
diff --git a/snippets/snippets/todo/lgci.ts b/snippets/snippets/todo/lgci.ts
new file mode 100644
index 0000000..7b38bfe
--- /dev/null
+++ b/snippets/snippets/todo/lgci.ts
@@ -0,0 +1,11 @@
+// Same as before
+type Todo = Readonly<{
+ id: number
+ text: string
+ done: boolean
+}>
+
+// Input is an array of Todo items: Todo[]
+function completeAll(todos: Todo[]) {
+ // ...
+}
diff --git a/snippets/snippets/todo/mnmy.ts b/snippets/snippets/todo/mnmy.ts
new file mode 100644
index 0000000..d72cfe2
--- /dev/null
+++ b/snippets/snippets/todo/mnmy.ts
@@ -0,0 +1,4 @@
+// Output is an array of Todo items: Todo[]
+function completeAll(todos: Todo[]): Todo[] {
+ // ...
+}
diff --git a/snippets/snippets/todo/mwrj.ts b/snippets/snippets/todo/mwrj.ts
new file mode 100644
index 0000000..5fbb963
--- /dev/null
+++ b/snippets/snippets/todo/mwrj.ts
@@ -0,0 +1,8 @@
+// After declaring todos as: readonly Todo[],
+// the following code WILL NOT compile:
+
+// Compile error - modifies the array
+todos[0] = { id: 1, text: '…', done: true }
+
+// Compile error - push() modifies the array
+todos.push({ id: 1, text: '…', done: true })
diff --git a/snippets/snippets/todo/szan.ts b/snippets/snippets/todo/szan.ts
new file mode 100644
index 0000000..140d75b
--- /dev/null
+++ b/snippets/snippets/todo/szan.ts
@@ -0,0 +1,6 @@
+// Make input todos as readonly array
+function completeAll(
+ todos: readonly Todo[]
+): Todo[] {
+ // ...
+}
diff --git a/src/components/CodeBlock.tsx b/src/components/CodeBlock.tsx
index 12c803e..2c9ab5f 100644
--- a/src/components/CodeBlock.tsx
+++ b/src/components/CodeBlock.tsx
@@ -20,7 +20,8 @@ const CodeBlock = ({
compile,
shouldHighlightResult,
resultError,
- tokenIndexIndentWorkaround
+ tokenIndexIndentWorkaround,
+ defaultErrorHighlight
}: {
snippet: string
shouldHighlight?: (lineIndex: number, tokenIndex: number) => boolean
@@ -33,6 +34,7 @@ const CodeBlock = ({
shouldHighlightResult?: (lineIndex: number, tokenIndex: number) => boolean
resultError?: boolean
tokenIndexIndentWorkaround?: number
+ defaultErrorHighlight?: boolean
}) => {
const [resultVisible, setResultVisible] = useState(defaultResultVisible)
const { radii, colors, ns, maxWidths, spaces, fontSizes } = useTheme()
@@ -88,21 +90,16 @@ const CodeBlock = ({
shouldHighlightResult(lineIndex, tokenIndex))) &&
css`
font-weight: bold;
- background: ${shouldHighlightResult && resultVisible && resultError
+ background: ${((shouldHighlightResult && resultVisible) ||
+ defaultErrorHighlight) &&
+ resultError
? colors('white')
: colors('yellowHighlight')};
- border-bottom: ${shouldHighlightResult &&
- resultVisible &&
+ border-bottom: ${((shouldHighlightResult && resultVisible) ||
+ defaultErrorHighlight) &&
resultError
- ? 'none'
+ ? `3px solid ${colors('red')}`
: `2px solid ${colors('darkOrange')}`};
- text-decoration: ${shouldHighlightResult &&
- resultVisible &&
- resultError
- ? 'underline'
- : 'none'};
- text-decoration-style: wavy;
- text-decoration-color: ${colors('red')};
`
}
language={noHighlight ? 'diff' : 'typescript'}
diff --git a/src/lib/snippets.ts b/src/lib/snippets.ts
index f6ffd96..b808f9e 100644
--- a/src/lib/snippets.ts
+++ b/src/lib/snippets.ts
@@ -530,6 +530,18 @@ function toggleTodo(
// ...
}`
+export const lgci = `// Same as before
+type Todo = Readonly<{
+ id: number
+ text: string
+ done: boolean
+}>
+
+// Input is an array of Todo items: Todo[]
+function completeAll(todos: Todo[]) {
+ // ...
+}`
+
export const lieq = `type Todo = {
id: number
text: string
@@ -547,6 +559,20 @@ console.log(\`{ id: 1, text: '…', done: false }\`)
console.log('Actual:')
console.log(result)`
+export const mnmy = `// Output is an array of Todo items: Todo[]
+function completeAll(todos: Todo[]): Todo[] {
+ // ...
+}`
+
+export const mwrj = `// After declaring todos as: readonly Todo[],
+// the following code WILL NOT compile:
+
+// Compile error - modifies the array
+todos[0] = { id: 1, text: '…', done: true }
+
+// Compile error - push() modifies the array
+todos.push({ id: 1, text: '…', done: true })`
+
export const njgr = `function toggleTodo(todo: Todo): Todo {
// Little Duckling’s refactoring is a
// bad refactoring because it modifies
@@ -605,6 +631,13 @@ export const reel = `function toggleTodo(todo) {
}
}`
+export const szan = `// Make input todos as readonly array
+function completeAll(
+ todos: readonly Todo[]
+): Todo[] {
+ // ...
+}`
+
export const tdbp = `// Takes an array of todo items and returns
// a new array where "done" is all true
function completeAll(todos) {
diff --git a/src/pages/todo.tsx b/src/pages/todo.tsx
index 119c387..968f4df 100644
--- a/src/pages/todo.tsx
+++ b/src/pages/todo.tsx
@@ -714,7 +714,7 @@ const Page = () => (
lineNumber <= 1}
+ shouldHighlight={lineIndex => lineIndex <= 1}
/>
>
)
@@ -739,9 +739,9 @@ const Page = () => (
The above code is equivalent to the following version:
- (lineNumber === 1 && tokenNumber >= 7 && tokenNumber <= 8) ||
- (lineNumber === 5 && tokenNumber >= 1)
+ shouldHighlight={(lineIndex, tokenIndex) =>
+ (lineIndex === 1 && tokenIndex >= 7 && tokenIndex <= 8) ||
+ (lineIndex === 5 && tokenIndex >= 1)
}
/>
@@ -773,8 +773,8 @@ const Page = () => (
In that case, we can write the following code:
- lineNumber === 11 && tokenNumber >= 1
+ shouldHighlight={(lineIndex, tokenIndex) =>
+ lineIndex === 11 && tokenIndex >= 1
}
/>
(
- (lineNumber === 0 && tokenNumber <= 2) ||
- (lineNumber === 8 &&
- ((tokenNumber >= 5 && tokenNumber <= 7) ||
- tokenNumber === 11))
+ shouldHighlight={(lineIndex, tokenIndex) =>
+ (lineIndex === 0 && tokenIndex <= 2) ||
+ (lineIndex === 8 &&
+ ((tokenIndex >= 5 && tokenIndex <= 7) || tokenIndex === 11))
}
/>
@@ -888,9 +887,9 @@ const Page = () => (
- (lineNumber === 1 && tokenNumber >= 7 && tokenNumber <= 8) ||
- (lineNumber === 5 && tokenNumber >= 1)
+ shouldHighlight={(lineIndex, tokenIndex) =>
+ (lineIndex === 1 && tokenIndex >= 7 && tokenIndex <= 8) ||
+ (lineIndex === 5 && tokenIndex >= 1)
}
/>
Next, let’s take a look at more non-trivial examples!
@@ -933,6 +932,126 @@ const Page = () => (
true.
+
+ Before implementing it,{' '}
+
+ let’s add some types for the input and output of this function
+ {' '}
+ to prevent mistakes!
+
+ >
+ )
+ },
+ {
+ title: (
+ <>
+ Adding types for completeAll()
+ >
+ ),
+ content: (
+ <>
+
+ First, we’ll specify the type for the input
+ parameter of completeAll(). It’s an array of{' '}
+ Todo items.{' '}
+
+ To specify an array type, we add [] next to the
+ type
+ {' '}
+ as follows:
+
+
+ lineIndex === 8 && tokenIndex >= 5 && tokenIndex <= 9
+ }
+ />
+
+ Second, let’s specify the return type. It’ll also
+ be an array of Todo items, so we’ll use the same
+ syntax as above:
+
+
+ lineIndex === 1 && tokenIndex >= 11 && tokenIndex <= 15
+ }
+ />
+
+ Third, we want to make sure that{' '}
+ completeAll() returns a new array and does NOT modify
+ the original array. Each item in the array is already{' '}
+ readonly, but the array itself is NOT{' '}
+ readonly yet.
+
+
+ To make the array itself readonly,{' '}
+
+ we’ll add the readonly keyword to{' '}
+ Todo[] like so:
+
+
+
+ lineIndex === 2 && tokenIndex >= 1
+ }
+ />
+
+
+ So for arrays, we use the readonly keyword
+ instead of the Readonly<...> mapped
+ type?
+
+ >
+ )
+ }
+ ]}
+ />
+
+ Yes, Little Duckling! We use the readonly keyword for
+ arrays. And by doing so,{' '}
+
+ TypeScript will prevent you from accidently modifying the array.
+
+
+
+ (lineIndex === 4 && tokenIndex <= 3) ||
+ (lineIndex === 7 && tokenIndex <= 2)
+ }
+ />
+
+
+ Awesome! So, can we start implementing{' '}
+ completeAll() now?
+
+ >
+ )
+ }
+ ]}
+ />
+
+ Actually:{' '}
+
+ There’s one more thing we’d like to do before we implement{' '}
+ completeAll()
+
+ . Let’s take a look at what that is!
+
>
)
},