Skip to content

Commit

Permalink
Reorganize page section (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
mildronize authored May 25, 2024
2 parents 9a291c8 + 11f9098 commit 9f8ced3
Show file tree
Hide file tree
Showing 22 changed files with 219 additions and 49 deletions.
Binary file modified bun.lockb
Binary file not shown.
50 changes: 30 additions & 20 deletions docs/.vitepress/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ export const shared = defineConfig({
});

/**
* Add Google Analytics
* Add Google Analytics
* @ref https://vitepress.dev/reference/site-config#example-using-google-analytics
* @param tagManagerId
* @returns
* @param tagManagerId
* @returns
*/
function googleAnalytics(tagManagerId: string): HeadConfig[] {
return [
Expand Down Expand Up @@ -66,22 +66,37 @@ export const baseSidebar = new Sidebar({
.addGroup("/", { text: "Start Reading" })
.add("/", "intro", { text: "Introduction", link: "/intro" })
.add("/", "type-safe", { text: "What is Type-safe", link: "/what-type-safe" })
.add("/", "when-type-safe", { text: "When Type-safe", link: "/when-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
* Design Guideline Section
*/
.addGroup("/data-structure", { text: "Data Structure" })
.add("/data-structure", "data-structure", {
.addGroup("/design-guideline", { text: "Design Guideline" })
.add("/design-guideline", "design-guideline", {
text: "Intro",
link: "/data-structure",
docFooterText: "Intro to Data Structure",
link: "/design-guideline",
docFooterText: "Intro to Design Guideline",
})
.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" })
.add("/design-guideline", "when-type-safe", { text: "When Type-safe", link: "/when-type-safe" })
.add("/design-guideline", "type-safe-level", { text: "Type-Safe Level", link: "/type-safe-level" })
.add("/design-guideline", "project-structure", { text: "Project Structure", link: "/project-structure" })
/**
* Basic Types Section
*/
.addGroup("/basic-types", { text: "Basic Types" })
.add("/basic-types", "basic-types", {
text: "Intro",
link: "/basic-types",
docFooterText: "Intro to Basic Types",
})
.add("/basic-types", "literal-types", { text: "Literal Types", link: "/literal-types" })
.add("/basic-types", "template-literal-types", {
text: "Template Literal Types",
link: "/template-literal-types",
})
.add("/basic-types", "tuple", { text: "Tuple Types", link: "/tuple" })
.add("/basic-types", "record-object", { text: "Record Types", link: "/record-object" })
.add("/basic-types", "generics", { text: "Generics", link: "/generics" })
/**
* Type Programming Section
*/
Expand All @@ -96,11 +111,6 @@ export const baseSidebar = new Sidebar({
.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" })
/**
Expand All @@ -117,9 +127,9 @@ export const baseSidebar = new Sidebar({
.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
* Framework Patterns Section
*/
.addGroup("/framework-pattern", { text: "Framework Pattern" })
.addGroup("/framework-pattern", { text: "Framework Patterns" })
.add("/framework-pattern", "framework-pattern", {
text: "Intro",
link: "/framework-pattern",
Expand Down
18 changes: 10 additions & 8 deletions docs/.vitepress/th.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,24 @@ export const thSidebar = baseSidebar
.overrideGroup("/", { text: "เริ่มต้นอ่าน" })
.override("/", "intro", { text: "บทนำ", prefix })
.override("/", "type-safe", { text: "ความหมายของ Type-safe", prefix })
.override("/","when-type-safe", { text: "เมื่อไหร่ควรใช้ Type-safe" })
.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("/design-guideline", { text: "แนวทางการออกแบบ" })
.override("/design-guideline", "design-guideline", { text: "บทนำ" })
.override("/design-guideline", "when-type-safe", { text: "เมื่อไหร่ควรใช้ Type-safe" })
.override("/design-guideline", "project-structure", { text: "โครงสร้างโปรเจกต์", prefix })
.overrideGroup("/basic-types", { text: "โครงสร้างข้อมูล" })
.override("/basic-types", "basic-types", { text: "บทนำ" })
.override("/basic-types", "literal-types", {})
.override("/basic-types", "tuple", {})
.override("/basic-types", "record-object", {})
.override("/basic-types", "template-literal-types", {})
.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: "รูปแบบการออกแบบ" })
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Data Structure
# Basic Types

Data Structures are a way of organizing and storing data so that they can be accessed and worked with efficiently. They define the relationship between the data, and the operations that can be performed on the data. There are many different types of data structures, generally built upon simpler primitive data types.

Expand Down
70 changes: 70 additions & 0 deletions docs/basic-types/generics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Generics

## Basic Generics

TBA...

## Understanding Type Inference from Function Arguments

When you pass a function as an argument, TypeScript will infer the type of the function based on the arguments passed to it. This is known as type inference.

```ts twoslash
function identity<T>(arg: T): T {
return arg;
}

identity(42); // number
// ^?

// End of Example
```

In the above example, TypeScript infers the type of `T` as `number` because the argument passed to the `identity` function is a number.

### Think Generic Param as a variable

Generics are like variables for types. When you define a generic type, you are defining a placeholder for a type that will be determined when the generic type is used.

Defining generic types is similar to defining variables, you can use in every place where it is in scope. For example below, `Path` is a generic type that can be used in the function signature and return type.

```ts twoslash
type Paths = {
"/": "home";
"/about": "about";
"/users": "users";
};

function routeTo<Path extends keyof Paths>(path: Path) {
return path as Path;
}

routeTo("/users");
//^?

// End of Example
```

Moreover, you can use generic with any type features such as template literal types.
If I want to function that recieve one more argument and return a string that is a combination of the two arguments, I can use template literal types with generics.

```ts twoslash
type Paths = {
"/": "home";
"/about": "about";
"/users": "users";
};

function routeTo<
Path extends keyof Paths,
Param extends string
>(path: Path, params: Param) {
return `${path}/${params}` as `${Path}/${Param}`;
}

routeTo("/users", '324');
// ^?

// End of Example
```

For example, the `routeTo` function takes two arguments: `path` and `params`. The `path` argument is a key of the `Paths` type, and the `params` argument is a string. The function returns a string that is a combination of the two arguments. So, the return type will be `"/users/324"`.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,10 @@
In TypeScript, template literal types are a powerful feature that allows you to create types by combining string literals and expressions. Template literal types are used to create types that depend on the values of other types. They are often used in generic types to create more flexible and reusable code.


## Basic Usage

TBA...



Checkout [TypeScript Awesome Template Literal Types](https://github.com/ghoullier/awesome-template-literal-types) for more resources.
File renamed without changes.
1 change: 1 addition & 0 deletions docs/design-guideline/design-guideline.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Design Guideline
File renamed without changes.
3 changes: 3 additions & 0 deletions docs/design-guideline/type-safe-level.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Type-safe Level

Type-safe level is a measure of how much a project is type-safe. It is a subjective measure and can be different from one person to another. However, it is important to have a common understanding of what it means to be type-safe.
File renamed without changes.
4 changes: 2 additions & 2 deletions docs/design-patterns/builder-pattern.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,11 @@ const baseSidebar = new Sidebar()
.addGroup("/", { text: "Start Reading", collapsed: true })
.addGroup("/type-programming", { text: "Type Programming", collapsed: true })
.addGroup("/type-programming/loop", { text: "Loop", collapsed: true })
.add("/type-programming/loop", "/intro", { text: "Introduction" });
.add("/type-programming/loop", "intro", { text: "Introduction" });

const thSidebar = baseSidebar.clone();

thSidebar.override("/type-programming/loop", "/intro", { text: "Mapped Types" });
thSidebar.override("/type-programming/loop", "intro", { text: "Mapped Types" });
```

In this example, we define a `Sidebar` class that uses a record object to manage sidebar items in Vitepress. The `Sidebar` class has two generic parameters: `Groups` and `Items`. The `Groups` parameter is a record object with keys of type `AbsoluteLink` and values of type `SidebarMetadata`. The `Items` parameter is a record object with keys of type `RelativeLink` and values of type `SidebarMetadata`.
Expand Down
31 changes: 19 additions & 12 deletions docs/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,31 @@ I am currently writing a new E-book. Please follow and support!This book is for

Moreover, I have not seen any books or articles that cover these topics. I hope this book will help you improve your TypeScript code quality and design. I will publish the book on Leanpub. I will update the progress on X (Twitter). Please follow me on X (Twitter) [@mildronize](https://x.com/mildronize). I've been working on this book for a while, and I hope to finish it soon. I would love to hear feedback from the community because at that time when I'm writing, I haven't seen anyone write about this yet.

## Table of Contents

- TypeScript Config
- Use strict
- Data Structure
- Use [literal type](./data-structure/literal-types) rathen than string
- Use [Record object](./data-structure/record-object.md) rather than list/array
- Use [Tuple](./data-structure/tuple.md) rather than list/array
- Design Patterns
- Use [builder pattern](./design-patterns/builder-pattern.md)
- Use [function argument](./design-patterns/function-argument.md) instead of plain object
- Use [function overload](./design-patterns/function-overload.md)
## Why I wrote this book

When I started learning TypeScript, I think design type-safe code is a bit challenging. I've seen many people use type-safe design patterns in their projects, but I couldn't find any resources that explain how to use them. It's too much subjective and hard to understand. I've learned type-safe design patterns from various modern TypeScript open-source projects, and write my own Azure Functions Framework called [Nammtham](https://nammatham.thaitype.dev/). I've learned a lot from these projects.

I decided to write this book to help other developers who are struggling with type-safe design patterns. I hope this book will help you improve your TypeScript code quality and design.

## Prerequisites
Please make sure you have a good understanding of TypeScript before reading this book. If you are new to TypeScript, I recommend reading the [TypeScript Handbook](https://www.typescriptlang.org/docs/handbook/intro.html) first.

Generics are a fundamental concept in TypeScript, so make sure you understand them. You can read the [Generics](https://www.typescriptlang.org/docs/handbook/2/generics.html) section of the TypeScript Handbook.

## How the book is structured

From the book prerequisites, it is recommended to have a good understanding of TypeScript before reading this book. However, if you are already familiar with TypeScript, you can jump to a specific section that interests you. Each section will provide the necessary prerequisites and type knowledge that you need to know before reading it. So, you don't necessarily have to read the book from start to finish.

The book is divided into several sections, each covering a different topic. Each section is linked together, the sections are as follows:

- Section 1: Start Reading
- Section 2: Design Guideline
- Section 3: Basic Types
- Section 4: Type Programming
- Section 5: Design Patterns
- Section 6: Framework Patterns
- Section 7: Performance

## Recommended Reading

- [Type-Level Programming](https://type-level-typescript.com/) e-book.
Expand Down
8 changes: 8 additions & 0 deletions docs/public/staticwebapp.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"trailingSlash": "never",
"responseOverrides": {
"404": {
"rewrite": "/404.html"
}
}
}
6 changes: 3 additions & 3 deletions docs/th/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ outline: deep
- การตั้งค่า TypeScript
- ใช้ strict
- โครงสร้างข้อมูล
- ใช้ [literal type](/data-structure/literal-types) แทน string
- ใช้ [Record object](/data-structure/record-object.md) แทน list/array
- ใช้ [Tuple](/data-structure/tuple.md) แทน list/array
- ใช้ [literal type](/basic-types/literal-types) แทน string
- ใช้ [Record object](/basic-types/record-object.md) แทน list/array
- ใช้ [Tuple](/basic-types/tuple.md) แทน list/array
- รูปแบบการออกแบบ
- ใช้ [builder pattern](/design-patterns/builder-pattern.md)
- ใช้ [function argument](/design-patterns/function-argument.md) แทน plain object
Expand Down
2 changes: 1 addition & 1 deletion docs/th/what-type-safe.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# การออกแบบชนิดข้อมูลแบบปลอดภัยคืออะไร? (Type-safe Design Patterns)

::: tip TL;DR:
**การออกแบบชนิดข้อมูลแบบปลอดภัย** (Type-safe) ช่วยให้แน่ใจว่าประเภทของข้อมูลในโปรแกรมถูกต้องและสอดคล้องกัน โดยเฉพาะในภาษาโปรแกรมสมัยใหม่อย่าง TypeScript ลักษณะสำคัญรวมถึงการใช้ประเภท generic และ [template literal types](/type-programming/template-literal-types), แนวทางการออกแบบแบบ builder (Builder Pattern), การคาดเดาชนิดข้อมูล (Automatic Type Inference), และการลดการซ้ำซ้อนของการประกาศชนิดข้อมูล ตัวอย่างของโครงการ TypeScript ที่ใช้การออกแบบชนิดข้อมูลแบบปลอดภัย ได้แก่ Zod, tRPC, Hono, และ Elysia
**การออกแบบชนิดข้อมูลแบบปลอดภัย** (Type-safe) ช่วยให้แน่ใจว่าประเภทของข้อมูลในโปรแกรมถูกต้องและสอดคล้องกัน โดยเฉพาะในภาษาโปรแกรมสมัยใหม่อย่าง TypeScript ลักษณะสำคัญรวมถึงการใช้ประเภท generic และ [template literal types](/basic-types/template-literal-types), แนวทางการออกแบบแบบ builder (Builder Pattern), การคาดเดาชนิดข้อมูล (Automatic Type Inference), และการลดการซ้ำซ้อนของการประกาศชนิดข้อมูล ตัวอย่างของโครงการ TypeScript ที่ใช้การออกแบบชนิดข้อมูลแบบปลอดภัย ได้แก่ Zod, tRPC, Hono, และ Elysia
:::

หลายคนในวงการโปรแกรมมิ่งมักพูดถึง **"การออกแบบชนิดข้อมูลแบบปลอดภัย"** (Type-safe) แต่มีน้อยคนที่จะพยายามให้คำนิยามที่ชัดเจน เพื่อความชัดเจนยิ่งขึ้น ลองพยายามอธิบายการออกแบบชนิดข้อมูลแบบปลอดภัยในบริบทของภาษาโปรแกรมสมัยใหม่อย่าง TypeScript ในความเข้าใจของผม
Expand Down
22 changes: 22 additions & 0 deletions docs/type-programming/conditional-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,25 @@ type IsArray<T> = T extends any[] ? "yes" : "no";
type Test1 = IsArray<number>; // "no"
type Test2 = IsArray<string[]>; // "yes"
```

## Using Infer

### Prerequisites
- [Template Literal Types](../basic-types/template-literal-types)

Infer is a keyword used in conditional types to infer the type of a variable based on a condition. Infer is often used in conjunction with the `extends` keyword to extract the type of a variable that matches a specific condition.

```ts twoslash
type FindPrefix<T> =
T extends `${infer Prefix}/${string}`
? Prefix
: 'Not Found';


type Test = FindPrefix<'api/users'>;
// ^?

// End of Example
```

For example above, the `FindPrefix` type extracts the prefix of a string that is separated by a `/`. If the string matches the pattern `${infer Prefix}/${string}`, the type `Prefix` is inferred as the prefix of the string. Otherwise, the type is set to `'Not Found'`.
Loading

0 comments on commit 9f8ced3

Please sign in to comment.