-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add First Draft with table of content (#1)
- Loading branch information
Showing
14 changed files
with
200 additions
and
177 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 was deleted.
Oops, something went wrong.
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,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 |
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,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`. |
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,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. |
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 @@ | ||
# 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]; | ||
``` |
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,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. |
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,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 |
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 @@ | ||
# 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 |
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 @@ | ||
# Examples | ||
|
||
List of libraries: | ||
- Zod | ||
- tRPC | ||
- Hono | ||
- Elysia | ||
- ts-odata-client |
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,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 | ||
|
Oops, something went wrong.