-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat(wip): add book route and nand2tetris page * feat: add Boolean Logic chapter * feat: add typescript-type-challenges-in-real-projects blog * feat: add real world type gymnastic blog * chore: ai to chatbot
- Loading branch information
1 parent
aecf76b
commit 57d293d
Showing
22 changed files
with
597 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
export default function Code({ html }) { | ||
return ( | ||
// biome-ignore lint/security/noDangerouslySetInnerHtml: <explanation> | ||
<div className="prose border rounded-md md:w-full w-[320px] overflow-hidden" dangerouslySetInnerHTML={{ __html: html }} /> | ||
) | ||
} | ||
import React from "react"; | ||
import { cn } from "@/lib/utils"; | ||
const Code = React.forwardRef(({ className, ...props }, ref) => ( | ||
<div ref={ref} className={cn("prose border rounded-md md:w-full w-[320px] ", className)} {...props} /> | ||
)) | ||
export default Code |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export default function Layout({ children }) { | ||
return ( | ||
<article className="prose p-12 prose-p:my-0">{children}</article> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { Blog } from "@/config"; | ||
|
||
|
||
const Lists = ({ title, items }) => ( | ||
<section> | ||
<h3>{title}</h3> | ||
<ul> | ||
{items.map(({ name, href }) => ( | ||
<li key={name}> | ||
<a | ||
aria-label={name} | ||
variant="link" | ||
className="no-underline text-md text-zinc-500 hover:text-zinc-800 text-primary underline-offset-4 hover:underline" | ||
href={href} | ||
> | ||
{name} | ||
</a> | ||
</li> | ||
))} | ||
</ul> | ||
</section> | ||
); | ||
|
||
export default function Page() { | ||
return ( | ||
<> | ||
<Lists title="Blog" items={Blog} /> | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { Blog } from "@/config" | ||
|
||
export async function data(pageContext) { | ||
const blog = Blog.find((project) => project.href === pageContext.urlParsed.pathname) | ||
return { | ||
blog | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import { useData } from "vike-react/useData" | ||
export default function Page() { | ||
const { blog } = useData() | ||
return ( | ||
<div className="flex flex-col"> | ||
<div className="font-medium text-base flex flex-col gap-1"> | ||
<p className="text-zinc-700">{blog.name}</p> | ||
<p className=" text-zinc-500 text-sm">{blog.time} · {blog.description}</p> | ||
</div> | ||
|
||
<h4>Boolean Logic</h4> | ||
<ul> | ||
<li>A Boolean function is a function that operates on binary inputs and returns binary outputs. </li> | ||
<li>Any Boolean function can be realized using <b>Nand</b>.</li> | ||
<li>De Morgan's laws are important rules in Boolean algebra: | ||
<ul> | ||
<li>Not (A And B) = Not A Or Not B</li> | ||
<li>Not (A Or B) = Not A And Not B</li> | ||
</ul> | ||
</li> | ||
</ul> | ||
|
||
<p>This is truth table for Nand.</p> | ||
<table> | ||
<thead> | ||
<tr> | ||
<th>A</th> | ||
<th>B</th> | ||
<th>A Nand B</th> | ||
</tr> | ||
</thead> | ||
<tbody className="text-center"> | ||
<tr> | ||
<td>0</td> | ||
<td>0</td> | ||
<td>1</td> | ||
</tr> | ||
<tr> | ||
<td>0</td> | ||
<td>1</td> | ||
<td>1</td> | ||
</tr> | ||
<tr> | ||
<td>1</td> | ||
<td>0</td> | ||
<td>1</td> | ||
</tr> | ||
<tr> | ||
<td>1</td> | ||
<td>1</td> | ||
<td>0</td> | ||
</tr> | ||
</tbody> | ||
</table> | ||
<p>If we set both A and B to the same variable X, the truth table is equal to the <b>Not</b> truth table.</p> | ||
<table> | ||
<thead> | ||
<tr> | ||
<th>X</th> | ||
<th>X</th> | ||
<th>X Nand X</th> | ||
</tr> | ||
</thead> | ||
<tbody className="text-center"> | ||
<tr> | ||
<td>0</td> | ||
<td>0</td> | ||
<td>1</td> | ||
</tr> | ||
<tr> | ||
<td>1</td> | ||
<td>1</td> | ||
<td>0</td> | ||
</tr> | ||
</tbody> | ||
</table> | ||
<p> So <b>Not X = X Nand X.</b></p> | ||
<br /> | ||
<p>Since <b>And</b> is equal to <b>Not Nand</b>,and <b>Not</b> can be expressed using <b>Nand</b>: </p> | ||
<p>A And B = Not (A Nand B) = (A Nand B) Nand (A Nand B)</p> | ||
<br /> | ||
<p>Accroding to De Morgan's laws, it can be proven that <b>Or</b> can also be expressed using <b>Nand</b>:</p> | ||
<p>A Or B = Not (Not A and Not B)</p> | ||
</div> | ||
) | ||
} |
57 changes: 57 additions & 0 deletions
57
src/pages/blog/typescript-type-challenges-in-real-projects/+Page.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import './style.css' | ||
import Code from "@/components/ui/code" | ||
import { useData } from "vike-react/useData" | ||
export default function Page() { | ||
const { html, html2, html3, html4, html5, blog } = useData() | ||
return ( | ||
<div className="flex flex-col"> | ||
<div className="font-medium text-base flex flex-col gap-1"> | ||
<p className="text-zinc-700">{blog.name}</p> | ||
<p className=" text-zinc-500 text-sm">{blog.time} · {blog.description}</p> | ||
</div> | ||
<h4>Background</h4> | ||
<div className='flex flex-col justify-center space-y-4'> | ||
<p> | ||
In my previous | ||
<a | ||
aria-label="Spectral Analysis" | ||
variant="link" | ||
className="mx-1 no-underline text-md text-zinc-500 hover:text-zinc-800 text-primary underline-offset-4 hover:underline" | ||
href="/project/data-visualization" | ||
> | ||
data visualization project | ||
</a> | ||
, I have a type issue. | ||
</p> | ||
<p> | ||
This project is about spectral analysis. It has many electrodes with different labels, such as electrode A, B, C. | ||
</p> | ||
<p>It can easily write a TypeScript type to constrain these keys:</p> | ||
<Code dangerouslySetInnerHTML={{ __html: html }} /> | ||
<p>But these electrodes can be combined in pairs. such as electeode A-B, A-C, B-C.</p> | ||
<p>You can add more electrode like this below:</p> | ||
<Code dangerouslySetInnerHTML={{ __html: html2 }} /> | ||
<p>However, as the number of keys increase, this type becomes hard to maintain.</p> | ||
|
||
</div> | ||
|
||
<h4>Solution</h4> | ||
<div className='flex justify-center flex-col space-y-4'> | ||
<p>What if this question is in JavaScript world?</p> | ||
<p>The first solution is to use a double loop: </p> | ||
<Code dangerouslySetInnerHTML={{ __html: html3 }} /> | ||
<p>The second solution is to use recursive:</p> | ||
<Code className="p-0" dangerouslySetInnerHTML={{ __html: html4 }} /> | ||
|
||
<p>It's easy to understanding the idea, in this type issue, we can use TypeScript generics to achieve.</p> | ||
<Code className="p-0" dangerouslySetInnerHTML={{ __html: html5 }} /> | ||
<ul> | ||
<li>T extends string[] means that the generic to accpet a string array.</li> | ||
<li>Further check if T is an array with at least on element. If so, it destructures the first element as F and the rest as R.</li> | ||
<li>CombKeys<R>: This is a recursive call to CombKeys to handle the remaining elements R.</li> | ||
<li>: never:if T is not an array , the result is never.</li> | ||
</ul> | ||
</div> | ||
</div> | ||
) | ||
} |
76 changes: 76 additions & 0 deletions
76
src/pages/blog/typescript-type-challenges-in-real-projects/+data.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import { codeToHtml } from 'shiki' | ||
import { rendererRich, transformerTwoslash } from '@shikijs/twoslash' | ||
import { Blog } from "@/config" | ||
export async function data(pageContext) { | ||
const html = await codeToHtml(`type ElectrodeKeys = 'A'|'B'|'C'`, { | ||
lang: 'ts', | ||
theme: 'vitesse-light' | ||
}); | ||
|
||
const html2 = await codeToHtml(`type ElectrodeKeys = 'A'|'B'|'C'|'A-B'|'A-C'|'B-C'`, { | ||
lang: 'ts', | ||
theme: 'vitesse-light' | ||
}); | ||
|
||
const html3 = await codeToHtml(`function generatePairs(arr:string[]) { | ||
const pairs = []; | ||
for (let i = 0; i < arr.length; i++) { | ||
for (let j = i + 1; j < arr.length; j++) { | ||
pairs.push(\`\${ arr[i]}-\${ arr[j]}\`); | ||
} | ||
} | ||
return pairs; | ||
}`, { | ||
lang: 'ts', | ||
theme: 'vitesse-light' | ||
}); | ||
|
||
const html4 = await codeToHtml(`function generatePairs(arr:string[]) { | ||
const pairs:string[] = [] | ||
function recursiveGenerate(currentIndex:number, currentPair:string[]) { | ||
if (currentPair.length === 2) { | ||
pairs.push(currentPair.join('-')); | ||
return; | ||
} | ||
for (let i = currentIndex; i < arr.length; i++) { | ||
recursiveGenerate(i + 1, [...currentPair, arr[i]]); | ||
} | ||
} | ||
recursiveGenerate(0, []); | ||
return pairs; | ||
}`, { | ||
lang: 'ts', | ||
theme: 'vitesse-light' | ||
}); | ||
|
||
|
||
|
||
|
||
const html5 = await codeToHtml( | ||
`type ElectrodeKeys = ['A','B','C']\ntype CombKeys<T extends string[]> =\n T extends [infer F extends string, ...infer R extends string[]] | ||
? \`\${F}-\${R[number]}\` | CombKeys<R> | ||
: never\ntype CombElectrodeKeys = CombKeys<ElectrodeKeys>`, { | ||
lang: 'ts', | ||
theme: 'vitesse-light', | ||
transformers: [ | ||
transformerTwoslash({ | ||
renderer: rendererRich() | ||
}) | ||
] | ||
} | ||
|
||
|
||
|
||
) | ||
const blog = Blog.find((blog) => blog.href === pageContext.urlParsed.pathname) | ||
return { | ||
html, | ||
html2, | ||
html3, | ||
html4, | ||
html5, | ||
blog | ||
} | ||
} |
Oops, something went wrong.