Skip to content

Commit

Permalink
Writing Type Programming Section & Improve Thai Readability (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
mildronize authored May 21, 2024
2 parents da93889 + 5593f18 commit 79dac4d
Show file tree
Hide file tree
Showing 24 changed files with 1,374 additions and 156 deletions.
13 changes: 7 additions & 6 deletions docs/.vitepress/en.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { DefaultTheme, defineConfig } from "vitepress";
import { sidebar } from "./shared";
import { defineConfig } from "vitepress";
import { baseSidebar } from "./shared";

export const enSidebar = baseSidebar.clone().toSidebarItems();
// console.log(JSON.stringify(enSidebar, null, 2));

// https://vitepress.dev/reference/site-config
export const en = defineConfig({
Expand All @@ -11,7 +14,7 @@ export const en = defineConfig({
{ text: "Book", link: "/intro" },
],

sidebar: sidebar(),
sidebar: enSidebar,

footer: {
message:
Expand All @@ -20,9 +23,7 @@ export const en = defineConfig({
},

editLink: {
pattern:
"https://github.com/mildronize/type-safe-design-pattern/tree/main/docs/:path",
pattern: "https://github.com/mildronize/type-safe-design-pattern/tree/main/docs/:path",
},
},
});

153 changes: 83 additions & 70 deletions docs/.vitepress/shared.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { DefaultTheme, defineConfig } from "vitepress";
import { defineConfig } from "vitepress";
import { transformerTwoslash } from "@shikijs/vitepress-twoslash";
const isCollapsed = true;
import { Sidebar } from "../../utils/utils";

export const shared = defineConfig({
lastUpdated: true,
Expand Down Expand Up @@ -40,72 +40,85 @@ interface SidebarOptions {
locale?: string;
}

export function sidebar(options?: SidebarOptions): DefaultTheme.SidebarItem[] {
const isCollapsed = options?.isCollapsed ?? true;
const lang = options?.locale ? `/${options.locale}` : "";
return [
{
text: "Start Reading",
collapsed: isCollapsed,
items: [
{ text: "Introduction", link: `${lang}/intro` },
{ text: "What is Type-safe", link: `${lang}/type-safe` },
{ text: "Project Structure", link: `${lang}/project-structure` },
{ text: "Glossary", link: `${lang}/glossary` },
{ text: "Examples", link: `${lang}/examples` },
],
},
{
text: "Data Structure",
collapsed: isCollapsed,
base: `${lang}/data-structure/`,
items: [
{ text: "Intro", link: "data-structure", docFooterText: "Intro to Data Structure" },
{ text: "Literal Types", link: "literal-types" },
{ text: "Tuple", link: "tuple" },
{ text: "Record Object", link: "record-object" },
],
},
{
text: "Type Programming",
collapsed: isCollapsed,
base: `${lang}/type-programming/`,
export const baseSidebar = new Sidebar({
collapsed: true,
extraMessage: "🚧",
})
/**
* Start Reading Section
*/
.addGroup("/", { text: "Start Reading" })
.add("/", "intro", { text: "Introduction", link: "/intro" })
.add("/", "type-safe", { text: "What is Type-safe", link: "/type-safe" })
.add("/", "project-structure", { text: "Project Structure", link: "/project-structure" })
.add("/", "glossary", { text: "Glossary", link: "/glossary" })
.add("/", "examples", { text: "Examples", link: "/examples" })
/**
* Data Structure Section
*/
.addGroup("/data-structure", { text: "Data Structure" })
.add("/data-structure", "data-structure", {
text: "Intro",
link: "/data-structure",
docFooterText: "Intro to Data Structure",
})
.add("/data-structure", "literal-types", { text: "Literal Types", link: "/literal-types" })
.add("/data-structure", "tuple", { text: "Tuple Types", link: "/tuple" })
.add("/data-structure", "record-object", { text: "Record Types", link: "/record-object" })
/**
* Type Programming Section
*/
.addGroup("/type-programming", { text: "Type Programming" })
.add("/type-programming", "type-programming", {
text: "Intro",
link: "/type-programming",
docFooterText: "Intro to Type Programming",
})
.add("/type-programming", "conditional-types", { text: "Conditional Types", link: "/conditional-types" })

items: [
{ text: "Intro", link: "type-programming", docFooterText: "Intro to Type Programming" },
{ text: "Conditional Types", link: "conditional-types" },
{ text: "Loop with Recursive Types", link: "loop-with-recursive-types" },
{ text: "Template Literal Types", link: "template-literal-types" },
{ text: "Testing", link: "testing" },
{ text: "Examples", link: "examples" },
],
},
{
text: "Design Patterns",
collapsed: isCollapsed,
base: `${lang}/design-patterns/`,
items: [
{ text: "Intro", link: "design-patterns", docFooterText: "Intro to Design Patterns" },
{ text: "Loosen and Tighten", link: "loosen-and-tighten" },
{ text: "Builder Pattern", link: "builder-pattern" },
{ text: "Function Overloading", link: "function-overload" },
{ text: "Function Argument", link: "function-argument" },
],
},
{
text: "Framework Pattern",
collapsed: isCollapsed,
base: `${lang}/framework-pattern/`,
items: [
{ text: "Intro", link: "framework-pattern", docFooterText: "Intro to Framework Pattern" },
{ text: "Config File", link: "config-file" },
],
},
{
text: "Performance",
collapsed: isCollapsed,
base: `${lang}/performance/`,
items: [{ text: "Intro", link: "performance", docFooterText: "Intro to Performance" }],
},
];
}
.addGroup("/type-programming/loop", { text: "Loop" })
.add("/type-programming/loop", "mapped-types", { text: "Mapped Types", link: "/mapped-types" })
.add("/type-programming/loop", "recursive-types", { text: "Recursive Types", link: "/recursive-types" })

.add("/type-programming", "template-literal-types", {
text: "Template Literal Types",
link: "/template-literal-types",
})
.add("/type-programming", "testing", { text: "Testing", link: "/testing" })
.add("/type-programming", "examples", { text: "Examples", link: "/examples" })
/**
* Design Patterns Section
*/
.addGroup("/design-patterns", { text: "Design Patterns" })
.add("/design-patterns", "design-patterns", {
text: "Intro",
link: "/design-patterns",
docFooterText: "Intro to Design Patterns",
})
.add("/design-patterns", "loosen-and-tighten", { text: "Loosen and Tighten", link: "/loosen-and-tighten" })
.add("/design-patterns", "builder-pattern", { text: "Builder Pattern", link: "/builder-pattern" })
.add("/design-patterns", "function-overload", { text: "Function Overloading", link: "/function-overload" })
.add("/design-patterns", "function-argument", { text: "Function Argument", link: "/function-argument" })
/**
* Framework Pattern Section
*/
.addGroup("/framework-pattern", { text: "Framework Pattern" })
.add("/framework-pattern", "framework-pattern", {
text: "Intro",
link: "/framework-pattern",
docFooterText: "Intro to Framework Pattern",
})
.add("/framework-pattern", "config-file", { text: "Config File", link: "/config-file" })
.add("/framework-pattern", "generate-dynamic-types", {
text: "Generate Dynamic Types",
link: "/generate-dynamic-types",
})
/**
* Performance Section
*/
.addGroup("/performance", { text: "Performance" })
.add("/performance", "performance", {
text: "Intro",
link: "/performance",
docFooterText: "Intro to Performance",
});
71 changes: 54 additions & 17 deletions docs/.vitepress/th.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,66 @@
import { defineConfig } from "vitepress";
import { sidebar } from "./shared";
import { baseSidebar } from "./shared";

const prefix = "/th";
/**
* Note: Use prefix only tranlated page, the page is not translated will remove the link.
*/
export const thSidebar = baseSidebar
.clone()
.overrideGroup("/", { text: "เริ่มต้นอ่าน" })
.override("/", "intro", { text: "บทนำ", prefix })
.override("/", "type-safe", { text: "ความหมายของ Type-safe", prefix })
.override("/", "project-structure", { text: "โครงสร้างโปรเจกต์", prefix })
.override("/", "glossary", { text: "คลังคำศัพท์", prefix })
.override("/", "examples", { text: "ตัวอย่าง", prefix })
.overrideGroup("/data-structure", { text: "โครงสร้างข้อมูล" })
.override("/data-structure", "data-structure", { text: "บทนำ" })
.override("/data-structure", "literal-types", {})
.override("/data-structure", "tuple", {})
.override("/data-structure", "record-object", {})
.overrideGroup("/type-programming", { text: "เขียนโปรแกรมด้วย Type" })
.override("/type-programming", "type-programming", { text: "บทนำ" })
.override("/type-programming", "conditional-types", { text: "เงื่อนไข (Conditional Types)" })
.overrideGroup("/type-programming/loop", { text: "การวนลูป" })
.override("/type-programming/loop", "mapped-types", {})
.override("/type-programming/loop", "recursive-types", {})
.override("/type-programming", "template-literal-types", {})
.override("/type-programming", "testing", { text: "การทดสอบ" })
.override("/type-programming", "examples", { text: "ตัวอย่าง" })
.overrideGroup("/design-patterns", { text: "รูปแบบการออกแบบ" })
.override("/design-patterns", "design-patterns", { text: "บทนำ" })
.override("/design-patterns", "loosen-and-tighten", { text: "ทำให้หลวมและแน่นขึ้น" })
.override("/design-patterns", "builder-pattern", { text: "รูปแบบ Builder Pattern" })
.override("/design-patterns", "function-overload", { text: "การใช้ Function หลายรูปแบบ" })
.override("/design-patterns", "function-argument", { text: "การใช้ Argument ชนิดข้อมูลเป็นฟังก์ชัน" })
.overrideGroup("/framework-pattern", { text: "การออกแบบของ Framework" })
.override("/framework-pattern", "framework-pattern", { text: "บทนำ" })
.override("/framework-pattern", "config-file", { text: "การใช้ไฟล์สำหรับการตั้งค่า" })
.override("/framework-pattern", "generate-dynamic-types", { text: "การสร้างชนิดข้อมูลแบบยืดหยุ่น" })
.overrideGroup("/performance", { text: "ประสิทธิภาพ" })
.override("/performance", "performance", { text: "บทนำ" })
.toSidebarItems();

export const th = defineConfig({
lang: "th",
description: "ไทย",

description: "รูปแบบการออกแบบพร้อมใช้งานโดยมีชนิดข้อมูลที่ปลอดภัยใน typescript สมัยใหม่",

themeConfig: {
nav: [
{ text: "หน้าแรก", link: "/th" },
{ text: "หนังสือ", link: "/th/intro" },
{ text: "หน้าแรก", link: prefix + "/" },
{ text: "หนังสือ", link: prefix + "/intro" },
],
sidebar: sidebar({
locale: "th",
}),
sidebar: thSidebar,

footer: {
message:
'เนื้อหาอยู่ภายใต้ใบอนุญาต <a href="https://creativecommons.org/licenses/by-nc-nd/4.0/" target="blank">CC BY-NC-ND 4.0</a>',
copyright: `ลิขสิทธิ์ © 2567-${new Date().getFullYear()+543} ธาดา หวังธรรมมั่ง`,
},

editLink: {
pattern:
"https://github.com/mildronize/type-safe-design-pattern/tree/main/docs/th/:path",
},
message:
'เนื้อหาอยู่ภายใต้ใบอนุญาต <a href="https://creativecommons.org/licenses/by-nc-nd/4.0/" target="blank">CC BY-NC-ND 4.0</a>',
copyright: `ลิขสิทธิ์ © 2567-${new Date().getFullYear() + 543} ธาดา หวังธรรมมั่ง`,
},

editLink: {
pattern: "https://github.com/mildronize/type-safe-design-pattern/tree/main/docs/th/:path",
},
},
});
32 changes: 31 additions & 1 deletion docs/data-structure/record-object.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,34 @@ In TypeScript, a record object is a type that represents an object with keys of
type User = Record<string, unknown>;
```

Mostly use with [builder pattern](../design-patterns//builder-pattern) to construct complex objects step by step.
Mostly use with [builder pattern](../design-patterns//builder-pattern) to construct complex objects step by step.

## Using Record Object for Enhanced Type Safety

Arrays in TypeScript are not inherently type-safe. For example:

```ts
type Tenant = {
name: string;
metadata: Record<string, unknown>;
}[];

```

In this case, we cannot use literal types with arrays. However, if we structure it as an object:

```ts
type Tenant = Record<'Provider' | 'Consumer', {
metadata: Record<string, unknown>
}>;
```

We can infer types from the keys, which are literals.

### Flexibility vs. Type Safety

If we require the flexibility of an array—such as when managing tenants with varying roles like provider, consumer, or potentially new roles in the future—we might still use an array. However, this approach lacks type safety, necessitating manual type checks and validations.

Conversely, using an object instead of an array ensures type safety. The challenge, however, is that TypeScript, being a statically typed language, does not allow us to derive literal types from runtime data. As a result, many developers opt to auto-generate type definitions (`.d.ts` files) to maintain type safety and reflect any configuration changes in the code.

This technique will be further explained in the chapter on Framework Patterns, specifically in the section on Generating Dynamic Types.
Loading

0 comments on commit 79dac4d

Please sign in to comment.