Skip to content

Commit

Permalink
chore: copy to astro
Browse files Browse the repository at this point in the history
  • Loading branch information
unional committed Oct 7, 2024
1 parent 360f3ee commit a3ffe23
Show file tree
Hide file tree
Showing 20 changed files with 578 additions and 28 deletions.
17 changes: 17 additions & 0 deletions .vscode/ltex.dictionary.en-US.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,20 @@ eslintrc

npm
pubDate
Blackbook
typescript-blackbook
@astrojs
sourcemap
declarationMap
tsc
video-url
jsonc
camelCase
PascalCase
straw-hat-adr-file-convention
ApiSpec
APISpec
apispec
npmignore
Deno
JSDoc
4 changes: 3 additions & 1 deletion apps/starlight/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ export default defineConfig({
base: 'typescript-blackbook',
integrations: [starlight({
title: 'TypeScript Blackbook',
favicon: './src/assets/logo.svg',
logo: { src:'./src/assets/logo.svg'},
social: {
"x.com": 'https://x.com/unional',
discord:'https://discord.gg/RwzcFpN5fv',
Expand All @@ -22,7 +24,7 @@ export default defineConfig({
label: 'Guides',
items: [
// Each item here is one entry in the navigation menu.
{ label: 'Example Guide', slug: 'guides/example' },
{ slug: 'guides/welcome' },
],
},
],
Expand Down
2 changes: 1 addition & 1 deletion apps/starlight/src/content/config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { z, defineCollection } from 'astro:content'
import { docsSchema } from '@astrojs/starlight/schema'
import { defineCollection, z } from 'astro:content'

const blogsCollection = defineCollection({
type: 'content',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
---
title: Creating rich comments
tags: [comment, documentation, DX]
---

You **should** add JSDoc comments to your code.

> Why?
For a long time, I do not do this.
My belief was that the code should be self-explanatory.

However, having the comments in the code,
especially for public facing code,
makes it a lot easier for consumer to use the code.

Especially if you can provide examples in the comments.

For example, the following is a comment for the `IsEqual` type in [type-plus]:

```ts
/**
* Checks `A` and `B` are equal.
*
* ```ts
* type R = IsEqual<1, 1> // true
* type R = IsEqual<any, any> // true
* type R = IsEqual<boolean, boolean> // true
* type R = IsEqual<true, true> // true
* type R = IsEqual<[1], [1]> // true
*
* type R = IsEqual<boolean, true> // false
* type R = IsEqual<any, 1> // false
* type R = IsEqual<[any], [1]> // false
* type R = IsEqual<{ a: 1 }, { a: 1; b: 2 }> // false
* ```
*
* Note that intersection type checks only works at first level.
* It cannot be check recursively,
* or else will run into infinite recursion if the type includes recursive types.
*/
export type IsEqual<A, B, Then = true, Else = false> = ...
```
---
You **should not** include import statements in the comment examples.
> Why?
Your code or type can be reused in different context.
The import statement might not be the same in different contexts.
For example, your code might be reused in another package.
So the import statement will provide the wrong information.
❌ Bad
```ts
/**
* Check if the type `T` is exactly `any`.
*
* ```ts
* import type { AnyType } from 'type-plus'
*
* type R = AnyType<any> // any
*
* type R = AnyType<never> // never
* type R = AnyType<unknown> // never
* type R = AnyType<string | boolean> // never
* ```
*/
export type AnyType<T, Then = T, Else = never> = ...
```
✅ Good
```ts
/**
* Check if the type `T` is exactly `any`.
*
* ```ts
* type R = AnyType<any> // any
*
* type R = AnyType<never> // never
* type R = AnyType<unknown> // never
* type R = AnyType<string | boolean> // never
* ```
*/
export type AnyType<T, Then = T, Else = never> = ...
```
[type-plus]: https://github.com/unional/type-plus
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
---
title: Naming Convention
tags: [file, folder, project, naming]
---

# Naming Convention

You **should** name your file and folder in `snake_case` or `kebab-case` instead of `camelCase` or `PascalCase`.

> Why?
Some file systems are case-insensitive (yes, I'm looking at you, Windows).
That means `ApiSpec == apispec == APISpec`.

To avoid confusion, `camelCase` and `PascalCase` should be avoided.
That leave us with `snake_case` or `kebab-case`.

The benefits of `snake_case` over `kebab-case` is that,
in most cases, operating system treats `snake_case` as a single word,
and treats `kebab-case` as a composed word.

For example, when you double-click on a `kebab-case` string,
a single word will be selected (i.e. either `kebab` or `case` will be selected).

On the other hand, double-click on a `snake_case` string will select the whole string.

The same goes to renaming.

Therefore, I would recommend `snake_case` over `kebab-case`,
even though `_` takes an additional pinky press to type.

But `kebab-case` is still a valid choice,
especially when you are using file-based routing.

---

You **should** name your file in nouns. i.e. `customer_order.ts` instead of `create_customer_order.ts`.

> Why?
You might have heard of Single Responsibility Principle and think that you should have one function per file.

That is utterly wrong and not what SRP means.

SRP is about putting related code together where they have the same reason to change.

Naming (and thus organizing) the file with nouns will significantly make your file and folder a lot more stable.

Meaning there will be less import path changes.

---

You **can** use `.` to create sub-category on filenames.

> Why
The name of the file should describe WHAT the file is about,
in terms of its context or business value.

For example, `customer_order.ts`.

However, there are situations that you want to further organize the code into addition categories,
so that it is easy to visualize as well as controlling the exposed API.

For example, you can do this:

```sh
customer_order.ts
customer_order.ctx.ts # context code for dependency injection
customer_order.internal.ts # code that you use internally, but exported for your tests.
customer_order.mock.ts # helper code for mocking the data during tests
customer_order.spec.ts # specification tests
customer_order.unit.ts # unit tests
customer_order.unit.electron.ts # unit tests only for electron
```

## References

Another interesting take from [Straw Hat's ADRs][straw-hat-adr-file-convention].

[straw-hat-adr-file-convention]: https://straw-hat-team.github.io/adr/3122196229/README.html
18 changes: 18 additions & 0 deletions apps/starlight/src/content/docs/guidelines/project/npmignore.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
title: ".npmignore file"
authors: [unional]
tags: [project]
---

The `.npmignore` file is used to keep stuff out of your package.

You **should not** use `.npmignore` file

> Why?
There are [problematic situations](https://medium.com/@jdxcode/for-the-love-of-god-dont-use-npmignore-f93c08909d8d) when using `.npmignore` file.

You can actually exclude files and folders using the [files field](./package-json#the-files-field).
There is no reason to use `.npmignore` file.

- <https://docs.npmjs.com/cli/v9/using-npm/developers#keeping-files-out-of-your-package>
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
slug: package-json
title: "package.json"
authors: [unional]
tags: [project, typescript, tsconfig]
---

## The `files` field

The `files` field is used to specify which files and folders to be included in the publish package.

You **should** always specify the `files` field.

> Why?
By default, files not excluded by `.gitignore` (or `.npmignore`) are included, which is not what you want.
Also, files that are excluded by `.gitignore` are not included, which is likely also not what you want.

So it is always better to be explicit and control them yourself.

For example, if the `files` field is removed from [type-plus],

files like `.changeset/*`, `.github/*`, `.vscode/*` are included,
while `cjs/*` and `esm/*` are not.

---

You **should** use `files` field to exclude test files.

For example, add this to your `files` field:

```json5
{
"files": [
// your package files
"cjs",
"esm",
"testing",
"ts",
// exclude test files
"!**/*.{spec,test,unit,accept,integrate,system,perf,stress}.*"
]
}
```

> Why?
Doing this allows you to keep your tsconfig setup simple.
You will always compile all files, including your test files.

This ensures that your test files does not contain any syntax error.

- <https://docs.npmjs.com/cli/v9/configuring-npm/package-json#files>

[type-plus]: https://github.com/unional/type-plus
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
slug: package_name
title: "Naming your package"
authors: [unional]
tags: [project]
---

When you create a package,
you always have to go through the painful process of naming your package.

While it is not specific to TypeScript,
it is still beneficial to follow certain guidelines to make your life a bit easier.

---

You **should** use `snake_case` for your package name.

> Why?
[NodeJS] is not opinionated about package names, but
[Deno] prohibits using `kebab-case` or `PascalCase` as module name.

Since [Deno] is likely to stay, you should use `snake_case` so that they are consistent.

---

You **should** name your package with nouns.

> Why?
Naming your package with verbs typically means your package is doing just one thing.

Of course, if that is what you want, that's fine.

But naming your package with nouns allows you to add similar features to your package, without causing confusion.

[Deno]: https://deno.land/x?page=2#Q&A
[NodeJS]: https://nodejs.org/
11 changes: 0 additions & 11 deletions apps/starlight/src/content/docs/guides/example.md

This file was deleted.

47 changes: 47 additions & 0 deletions apps/starlight/src/content/docs/guides/welcome.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
title: Welcome
description: Welcome old and new readers to TypeScript Blackbook.
---

Welcome to TypeScript Blackbook.

This book focus on *how to get the most out of TypeScript with minimal effort*.

To achieve that goal,
following some coding styles is a good place to start.

However, just following *what to do* can only go so far.
You need to know *why* should you write code in certain way,
*what* are the *trade-offs* you are making,
as well as the design and the limitations of the language itself,
so that you have the right *mindset* and *approach* the problem and come to a solution effectively.

Therefore, this book covers more than just style guide and best practices.

It needs to cover everything related to TypeScript in order to achieve that goal.

<!-- This book is organized into a few sections:
- How to TypeScript: Designs, limitations, and approach
- TypeScript (and JavaScript) syntax and features
- Coding Styles and Guidelines
- Supporting Tools -->

Learning everything about TypeScript is not easy.

The language itself is pretty complex,
and both TypeScript and JavaScript evolves at a rapid pace.
So it can be quite overwhelming if you are just starting out.

I would recommend having a quick read through of the [How to TypeScript] section,
and then check out the [Supporting Tools] section to find out how to set up your project,
and use the rest of the book for reference as you need them.

Having that said,
I'm in the process of updating this book.

Most of the information are still in their old format.
So please head over to the [GitHub repo] to look for the original content for the time being.

[GitHub repo]: https://github.com/unional/typescript-blackbook
[TypeScript Handbook]: https://www.typescriptlang.org/docs/handbook/intro.html
Loading

0 comments on commit a3ffe23

Please sign in to comment.