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/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/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 36ac729..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,19 @@ 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) { + // ... +}` + export const tgvw = `const bar: Todo = { text: '…', done: true diff --git a/src/pages/todo.tsx b/src/pages/todo.tsx index 4286142..968f4df 100644 --- a/src/pages/todo.tsx +++ b/src/pages/todo.tsx @@ -714,7 +714,7 @@ const Page = () => (
The above code is equivalent to the following version:
@@ -773,8 +773,8 @@ const Page = () => (
In that case, we can write the following code:
@@ -858,7 +857,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. You should still write + tests in TypeScript!)
This especially useful{' '} @@ -872,7 +873,9 @@ const Page = () => (
@@ -884,35 +887,174 @@ const Page = () => (
Next, let’s take a look at more non-trivial examples!
> ) }, - // { - // title: <>Mark all as completed>, - // content: ( - // <> - //
+ Some todo apps allow you to{' '}
+
+ 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.
+
+ Before implementing it,{' '}
+
completeAll()
+ >
+ ),
+ content: (
+ <>
+
+ First, we’ll specify the type for the input
+ parameter of completeAll(). It’s an array of{' '}
+ Todo items.{' '}
+ [] next to the
+ type
+
+ 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:
+
+ 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,{' '}
+ readonly keyword to{' '}
+ Todo[] like so:
+
+ 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,{' '}
+
+ Awesome! So, can we start implementing{' '}
+ completeAll() now?
+
+ Actually:{' '}
+ completeAll()
+