Skip to content

Commit

Permalink
Add First Draft with table of content (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
mildronize authored May 17, 2024
2 parents ee7b976 + 5f1029f commit fba10b2
Show file tree
Hide file tree
Showing 14 changed files with 200 additions and 177 deletions.
43 changes: 32 additions & 11 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,49 @@ export default defineConfig({
// https://vitepress.dev/reference/default-theme-config
nav: [
{ text: "Home", link: "/" },
{ text: "Examples", link: "/markdown-examples" },
{ text: "Book", link: "/intro" },
],

sidebar: [
{
text: "Examples",
text: "Start Reading",
collapsed: true,
items: [
// { text: "Markdown Examples", link: "/markdown-examples" },
// { text: "Runtime API Examples", link: "/api-examples" },
{ text: "TypeScript", link: "/typescript"},
{ text: "Use Cases", link: "/use-cases"},
{ text: "Introduction", link: "/intro" },
{ text: "Examples", link: "/examples" },
{ text: "Use Cases", link: "/use-cases" },
],
},
{
text: "Data Structure",
collapsed: true,
items: [
{ text: "Intro", link: "/data-structure/data-structure" },
{ text: "Literal String", link: "/data-structure/literal-string" },
{ text: "Tuple", link: "/data-structure/tuple" },
{ text: "Record Object", link: "/data-structure/record-object" },
],
},
{
text: "Design Patterns",
collapsed: true,
items: [
{ text: "Intro", link: "/design-patterns/design-patterns" },
{ text: "Builder Pattern", link: "/design-patterns/builder-pattern" },
{ text: "Function Overloading", link: "/design-patterns/function-overload" },
{ text: "Function Argument", link: "/design-patterns/function-argument" },
],
},
],

socialLinks: [
{ icon: "github", link: "https://github.com/vuejs/vitepress" },
{
icon: "github",
link: "https://github.com/mildronize/type-safe-design-pattern",
},
],
},
markdown: {
codeTransformers: [
transformerTwoslash()
]
}
codeTransformers: [transformerTwoslash()],
},
});
49 changes: 0 additions & 49 deletions docs/api-examples.md

This file was deleted.

10 changes: 10 additions & 0 deletions docs/data-structure/data-structure.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Intro

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.

In TypeScript, data structures are used to represent data in a structured way. They can be used to store data in a way that makes it easy to access and manipulate. TypeScript provides several built-in data structures, such as arrays, tuples, and objects, as well as the ability to define custom data structures using interfaces and classes.

In order to create type-safe data structures in TypeScript, it is important to understand the different types of data structures available, how they work, and when to use them. This guide will provide an overview of some of the most common data structures in TypeScript, and how to use them effectively in your code.

Not all data structures are type-safe, but some of them are very useful in TypeScript. Here are some data structures that are commonly used in TypeScript:
- Use [literal type](./literal.md) rathen than string
3 changes: 3 additions & 0 deletions docs/data-structure/literal-string.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Literal String

In TypeScript, a literal string is a string that has a specific value. For example, the string `"hello"` is a literal string with the value `hello`.
9 changes: 9 additions & 0 deletions docs/data-structure/record-object.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Record Object

In TypeScript, a record object is a type that represents an object with keys of type `string` and values of type `unknown`. The `Record` type is a built-in utility type that allows you to define a record object with specific keys and values.

```ts twoslash
type User = Record<string, unknown>;
```

Mostly use with [builder pattern](../design-patterns//builder-pattern) to construct complex objects step by step.
8 changes: 8 additions & 0 deletions docs/data-structure/tuple.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Tuple

In TypeScript, a tuple is a type that represents an array with a fixed number of elements. The elements of a tuple can have different types, and the order of the elements is fixed.

```ts twoslash
type Point = [number, number];
const point: Point = [10, 20];
```
28 changes: 6 additions & 22 deletions docs/typescript.md → docs/design-patterns/builder-pattern.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,7 @@
---
outline: deep
---
# Builder Pattern

# TypeScript
The builder pattern is a creational design pattern that allows constructing complex objects step by step. The pattern is useful when the construction of an object is complex and requires multiple steps. The builder pattern is used to construct a complex object from simple objects step by step.

After examining the code of several well-known open-source projects such as Zod, tRPC, Hono, Elysia, and ts-odata-client.

## TypeScript Config
Use strict

## Use literal instead of string


## Use object rather than list/array
## Use tuple rather than list/array
## Use builder pattern

```ts twoslash
class Inventory<Items extends Record<string, unknown> = {}> {
Expand Down Expand Up @@ -51,10 +38,7 @@ type A = typeof inventory.items;
//
```

## Use predicate function instead of plain object
## Use function overload

```ts twoslash
console.log('hello')
// ^?
```
## Example Projects
- Hono
- Elysia
- Zod
9 changes: 9 additions & 0 deletions docs/design-patterns/design-patterns.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Design Patterns

In order to write type-safe and maintainable code in TypeScript, it is important to follow best practices and design patterns. Design patterns are reusable solutions to common problems that arise when writing software. They provide a way to structure code in a way that is easy to understand, maintain, and extend.

Not all design pattern meet type-safety, but some of them are very useful in TypeScript. Here are some design patterns that are commonly used in TypeScript:

- [Use builder pattern](./builder-pattern.md) when constructing complex objects step by step, passing type information along the way.
- [Use function argument instead of plain object](./function-argument.md) to enforce type safety and avoid runtime errors.
- [Use function overload](./function-overload.md) to create multiple functions with the same name but different parameters, achieving polymorphism in programming languages that do not support it natively.
42 changes: 42 additions & 0 deletions docs/design-patterns/function-argument.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Function Argument

A function argument is a value passed to a function when it is called. Arguments are used to provide input to the function so that it can perform its task. Functions can have zero or more arguments, and the number of arguments a function can accept is determined by its signature.

## Examples

```ts
import { ODataExpression} from 'ts-odata-client';

const result = ODataExpression.forV4<User>()
.filter((p) => p.firstName.$equals("john"))
.build();

console.log(results);
```

Implementing a function argument instead of a plain object:

```ts
export class ODataQueryBase<T, U = ExcludeProperties<T, unknown[]>> {
public filter(
predicate:
| BooleanPredicateBuilder<T>
| ((builder: EntityProxy<T, true>, functions: FilterAccessoryFunctions<T>) => BooleanPredicateBuilder<T>),
) {
if (typeof predicate === "function")
predicate = predicate(
this.provider[createProxiedEntity]() as unknown as EntityProxy<T, true>,
new FilterAccessoryFunctions<T>(),
);

const expression = new Expression(ExpressionOperator.Predicate, [predicate], this.expression);
return this.provider.createQuery<T, U>(expression);
}
}
```

From [ts-odata-client](https://github.com/cbrianball/ts-odata-client/blob/7b55184beebe5a08437863035f7bac29c341025a/src/lib/ODataQueryBase.ts#L106-L119)


## Example Projects
- ts-odata-client
30 changes: 30 additions & 0 deletions docs/design-patterns/function-overload.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Function Overloading

Function overloading is a feature that allows creating multiple functions with the same name but different parameters. It is a way to achieve polymorphism in programming languages that do not support it natively.

## Examples

```ts
import { ODataQueryProvider } from 'ts-odata-client';

export class ODataV4QueryProvider extends ODataQueryProvider {
executeQueryAsync<T extends ODataResponse>(expression?: Expression): Promise<T>;
executeQueryAsync<T extends ODataResponse>(odataUrl: string): Promise<T>;
async executeQueryAsync<T extends ODataResponse>(value?: Expression | string): Promise<T> {
if (typeof value !== "string") value = this.buildQuery(value);
const response = await this.sendRequest(value);

if (response.ok) {
return (await response.json()) as T;
}

throw new Error(JSON.stringify(await response.json()));
}
}
```

From the example above, the `executeQueryAsync` method is overloaded to accept either an `Expression` or a `string` parameter. This allows the method to be called with different types of arguments while maintaining the same name. From [ts-odata-client](https://github.com/cbrianball/ts-odata-client/blob/7b55184beebe5a08437863035f7bac29c341025a/src/lib/ODataV4QueryProvider.ts#L35-L46)

## Example Projects
- Hono
- ts-odata-client
8 changes: 8 additions & 0 deletions docs/examples.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Examples

List of libraries:
- Zod
- tRPC
- Hono
- Elysia
- ts-odata-client
20 changes: 10 additions & 10 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,21 @@ layout: home
hero:
name: "Type-safe Design Pattern"
text: "in Modern TypeScript"
tagline: Ready to use design Pattern for type-safe approach in modern typescript
tagline: This book provide ready to use design pattern for type-safe approach in modern typescript <br />by Thada Wangthammang
actions:
- theme: brand
text: Starting Reading
link: /typescript
link: /intro
- theme: alt
text: Use Cases
link: /use-cases
text: Design Patterns
link: /design-patterns/design-patterns

features:
- title: Feature A
details: Lorem ipsum dolor sit amet, consectetur adipiscing elit
- title: Feature B
details: Lorem ipsum dolor sit amet, consectetur adipiscing elit
- title: Feature C
details: Lorem ipsum dolor sit amet, consectetur adipiscing elit
- title: Next Level TypeScript
details: Level up your TypeScript skills with advanced design patterns and best practices
- title: Data Structure
details: Not all data structure are type-safe, this book provide ready to use data structure for type-safe approach
- title: Design Patterns
details: Not all design pattern meet type-safety, this book provide ready to use design pattern for type-safe approach
---

33 changes: 33 additions & 0 deletions docs/intro.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
outline: deep
---

# Introduction

::: info
This book is more advanced than the TypeScript Handbook. It is intended for developers who are already familiar with TypeScript and are looking to improve their code quality and design.
:::

This book is a collection of TypeScript best practices and design patterns. It is intended to be a guide for developers who are looking to improve their TypeScript code quality and design. The book covers a wide range of topics, including TypeScript configuration, data structures, design patterns, and more.

After examining the code of several well-known open-source projects such as Zod, tRPC, Hono, Elysia, and ts-odata-client.

## Recommended Reading
- [Type-Level Programming](https://type-level-typescript.com/)

## Table of Contents

- TypeScript Config
- Use strict
- Data Structure
- Literal
- Tuple
- Record Object
- Design Patterns
- Use literal instead of string
- Use object rather than list/array
- Use tuple rather than list/array
- Use builder pattern
- Use function argument instead of plain object
- Use function overload

Loading

0 comments on commit fba10b2

Please sign in to comment.