From a3ffe23614d6959884a7e6fb6ee906c431dca518 Mon Sep 17 00:00:00 2001 From: unional Date: Mon, 7 Oct 2024 00:13:18 -0700 Subject: [PATCH] chore: copy to astro --- .vscode/ltex.dictionary.en-US.txt | 17 ++++ apps/starlight/astro.config.mjs | 4 +- apps/starlight/src/content/config.ts | 2 +- .../guidelines/documentations/comments.md | 93 +++++++++++++++++++ .../files-and-folders/naming-conventions.mdx | 81 ++++++++++++++++ .../docs/guidelines/project/npmignore.mdx | 18 ++++ .../docs/guidelines/project/package-json.mdx | 55 +++++++++++ .../docs/guidelines/project/package-name.mdx | 38 ++++++++ .../src/content/docs/guides/example.md | 11 --- .../src/content/docs/guides/welcome.md | 47 ++++++++++ apps/starlight/src/content/docs/index.mdx | 2 +- .../src/content/docs/reference/example.md | 11 --- .../docs/tips/_type_cannot_be_named.md | 15 +++ .../docs/tsconfig/_isolated_modules.mdx | 12 +++ .../docs/tsconfig/_module_resolution.mdx | 11 +++ .../content/docs/tsconfig/declaration-map.mdx | 36 +++++++ .../docs/typescript-features/_type_guard.mdx | 66 +++++++++++++ .../typescript-features/assertion_funtion.mdx | 82 ++++++++++++++++ docs/pages/00-updates/README.md | 2 +- .../guidelines/documentations/comments.md | 3 +- 20 files changed, 578 insertions(+), 28 deletions(-) create mode 100644 apps/starlight/src/content/docs/guidelines/documentations/comments.md create mode 100644 apps/starlight/src/content/docs/guidelines/files-and-folders/naming-conventions.mdx create mode 100644 apps/starlight/src/content/docs/guidelines/project/npmignore.mdx create mode 100644 apps/starlight/src/content/docs/guidelines/project/package-json.mdx create mode 100644 apps/starlight/src/content/docs/guidelines/project/package-name.mdx delete mode 100644 apps/starlight/src/content/docs/guides/example.md create mode 100644 apps/starlight/src/content/docs/guides/welcome.md delete mode 100644 apps/starlight/src/content/docs/reference/example.md create mode 100644 apps/starlight/src/content/docs/tips/_type_cannot_be_named.md create mode 100644 apps/starlight/src/content/docs/tsconfig/_isolated_modules.mdx create mode 100644 apps/starlight/src/content/docs/tsconfig/_module_resolution.mdx create mode 100644 apps/starlight/src/content/docs/tsconfig/declaration-map.mdx create mode 100644 apps/starlight/src/content/docs/typescript-features/_type_guard.mdx create mode 100644 apps/starlight/src/content/docs/typescript-features/assertion_funtion.mdx diff --git a/.vscode/ltex.dictionary.en-US.txt b/.vscode/ltex.dictionary.en-US.txt index 8dd294fa..81489c77 100644 --- a/.vscode/ltex.dictionary.en-US.txt +++ b/.vscode/ltex.dictionary.en-US.txt @@ -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 diff --git a/apps/starlight/astro.config.mjs b/apps/starlight/astro.config.mjs index 6cab683f..939d19df 100644 --- a/apps/starlight/astro.config.mjs +++ b/apps/starlight/astro.config.mjs @@ -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', @@ -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' }, ], }, ], diff --git a/apps/starlight/src/content/config.ts b/apps/starlight/src/content/config.ts index cec00f07..d7506bc2 100644 --- a/apps/starlight/src/content/config.ts +++ b/apps/starlight/src/content/config.ts @@ -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', diff --git a/apps/starlight/src/content/docs/guidelines/documentations/comments.md b/apps/starlight/src/content/docs/guidelines/documentations/comments.md new file mode 100644 index 00000000..b9ce07b6 --- /dev/null +++ b/apps/starlight/src/content/docs/guidelines/documentations/comments.md @@ -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 // true + * type R = IsEqual // true + * type R = IsEqual // true + * type R = IsEqual<[1], [1]> // true + * + * type R = IsEqual // false + * type R = IsEqual // 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 = ... +``` + +--- + +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 + * + * type R = AnyType // never + * type R = AnyType // never + * type R = AnyType // never + * ``` + */ +export type AnyType = ... +``` + +✅ Good + +```ts +/** + * Check if the type `T` is exactly `any`. + * + * ```ts + * type R = AnyType // any + * + * type R = AnyType // never + * type R = AnyType // never + * type R = AnyType // never + * ``` + */ +export type AnyType = ... +``` + +[type-plus]: https://github.com/unional/type-plus diff --git a/apps/starlight/src/content/docs/guidelines/files-and-folders/naming-conventions.mdx b/apps/starlight/src/content/docs/guidelines/files-and-folders/naming-conventions.mdx new file mode 100644 index 00000000..657d2d80 --- /dev/null +++ b/apps/starlight/src/content/docs/guidelines/files-and-folders/naming-conventions.mdx @@ -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 diff --git a/apps/starlight/src/content/docs/guidelines/project/npmignore.mdx b/apps/starlight/src/content/docs/guidelines/project/npmignore.mdx new file mode 100644 index 00000000..3ca6fd2a --- /dev/null +++ b/apps/starlight/src/content/docs/guidelines/project/npmignore.mdx @@ -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. + +- diff --git a/apps/starlight/src/content/docs/guidelines/project/package-json.mdx b/apps/starlight/src/content/docs/guidelines/project/package-json.mdx new file mode 100644 index 00000000..d7e11eeb --- /dev/null +++ b/apps/starlight/src/content/docs/guidelines/project/package-json.mdx @@ -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. + +- + +[type-plus]: https://github.com/unional/type-plus diff --git a/apps/starlight/src/content/docs/guidelines/project/package-name.mdx b/apps/starlight/src/content/docs/guidelines/project/package-name.mdx new file mode 100644 index 00000000..dedaadbb --- /dev/null +++ b/apps/starlight/src/content/docs/guidelines/project/package-name.mdx @@ -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/ diff --git a/apps/starlight/src/content/docs/guides/example.md b/apps/starlight/src/content/docs/guides/example.md deleted file mode 100644 index ebd0f3bc..00000000 --- a/apps/starlight/src/content/docs/guides/example.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Example Guide -description: A guide in my new Starlight docs site. ---- - -Guides lead a user through a specific task they want to accomplish, often with a sequence of steps. -Writing a good guide requires thinking about what your users are trying to do. - -## Further reading - -- Read [about how-to guides](https://diataxis.fr/how-to-guides/) in the Diátaxis framework diff --git a/apps/starlight/src/content/docs/guides/welcome.md b/apps/starlight/src/content/docs/guides/welcome.md new file mode 100644 index 00000000..44ac324b --- /dev/null +++ b/apps/starlight/src/content/docs/guides/welcome.md @@ -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. + + + +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 diff --git a/apps/starlight/src/content/docs/index.mdx b/apps/starlight/src/content/docs/index.mdx index ac11b5e5..9d43035c 100644 --- a/apps/starlight/src/content/docs/index.mdx +++ b/apps/starlight/src/content/docs/index.mdx @@ -8,7 +8,7 @@ hero: file: ../../assets/logo.svg actions: - text: Start reading - link: /typescript-blackbook/guides/example/ + link: /typescript-blackbook/guides/welcome/ icon: right-arrow - text: Check out the blogs link: /typescript-blackbook/blogs/ diff --git a/apps/starlight/src/content/docs/reference/example.md b/apps/starlight/src/content/docs/reference/example.md deleted file mode 100644 index 0224f096..00000000 --- a/apps/starlight/src/content/docs/reference/example.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Example Reference -description: A reference page in my new Starlight docs site. ---- - -Reference pages are ideal for outlining how things work in terse and clear terms. -Less concerned with telling a story or addressing a specific use case, they should give a comprehensive outline of what you're documenting. - -## Further reading - -- Read [about reference](https://diataxis.fr/reference/) in the Diátaxis framework diff --git a/apps/starlight/src/content/docs/tips/_type_cannot_be_named.md b/apps/starlight/src/content/docs/tips/_type_cannot_be_named.md new file mode 100644 index 00000000..fef55548 --- /dev/null +++ b/apps/starlight/src/content/docs/tips/_type_cannot_be_named.md @@ -0,0 +1,15 @@ +# Type + +When using a package written in TypeScript, + +- Generic default value +- Properties + + +```ts +export type Foo = { + bar: Boo +} + +export type Koo = Foo & { a: number } +``` diff --git a/apps/starlight/src/content/docs/tsconfig/_isolated_modules.mdx b/apps/starlight/src/content/docs/tsconfig/_isolated_modules.mdx new file mode 100644 index 00000000..2f52b37d --- /dev/null +++ b/apps/starlight/src/content/docs/tsconfig/_isolated_modules.mdx @@ -0,0 +1,12 @@ +--- +slug: isolated_modules +title: "Isolated Modules" +authors: [unional] +tags: [typescript, tsconfig] +--- + +You **should** turn on `isolatedModules`. + +> Why? + +`SFT` diff --git a/apps/starlight/src/content/docs/tsconfig/_module_resolution.mdx b/apps/starlight/src/content/docs/tsconfig/_module_resolution.mdx new file mode 100644 index 00000000..238105d7 --- /dev/null +++ b/apps/starlight/src/content/docs/tsconfig/_module_resolution.mdx @@ -0,0 +1,11 @@ +# Module Resolution + +You **should** use `Node16` when possible. + +It depends on your dependencies. + +Problem with source map + + +[tsconfig#module]: https://www.typescriptlang.org/tsconfig#module +[tsconfig.es2022]: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-5.html#module-es2022 diff --git a/apps/starlight/src/content/docs/tsconfig/declaration-map.mdx b/apps/starlight/src/content/docs/tsconfig/declaration-map.mdx new file mode 100644 index 00000000..1db427f5 --- /dev/null +++ b/apps/starlight/src/content/docs/tsconfig/declaration-map.mdx @@ -0,0 +1,36 @@ +--- +title: Declaration Map +tags: [typescript, tsconfig] +--- + +# Declaration Map + +[![Video][video-image]][video-url] + +You **should** set [`declarationMap`] to `true`. + +> Why? + +The tells `tsc` to generate sourcemap for your declaration files. + +This enables "Go to Source Definition" features in supporting editors like VS Code. + +It makes your code easier to read and understand. + +Remember to include your TypeScript source code into the package distribution, +so that user of your library can navigate to the included source code. + +i.e. add this in your `package.json`: + +```jsonc +{ + "files": [ + // ... + "src" + ] +} +``` + +[`declarationMap`]: https://www.typescriptlang.org/tsconfig#declarationMap +[video-image]: https://img.youtube.com/vi/IRvy_4xgPLQ/0.jpg +[video-url]: https://www.youtube.com/watch?v=IRvy_4xgPLQ diff --git a/apps/starlight/src/content/docs/typescript-features/_type_guard.mdx b/apps/starlight/src/content/docs/typescript-features/_type_guard.mdx new file mode 100644 index 00000000..211d92e3 --- /dev/null +++ b/apps/starlight/src/content/docs/typescript-features/_type_guard.mdx @@ -0,0 +1,66 @@ +--- +title: "Type guard" +authors: [unional] +tags: [typescript] +--- + +[User-defined type guard functions][type_guard] is a function which its return type is specified as `x as T`. + +It is introduced in TypeScript 1.6. + +For example: + +```ts +function isBool(x: unknown): x is boolean { + return typeof x === 'boolean'; +} + +let value = 'true' as unknown + +if (isBool(value)) { + // `value` is narrowed to boolean +} +``` + +--- + +You **do not** need to write type guard functions for simple cases. + +> Why? + +TypeScript control flow analysis recognize many basic patterns and perform narrowing automatically. + +For example: + +```ts +let value: number | string = 123 + +if (typeof value === 'number') { + // `value` is narrowed to number +} +``` + +[Playground](https://www.typescriptlang.org/play?#code/DYUwLgBAbghsCuIBcEIDt4FsBGIBOEAPqgM5h4CWaA5hALwQCMATAMwCwAUFxQGYQAKMAE8ADiAD2-WAhD06DAOQYc+RQEoIAby4BIAPT6IAAxmJjECiXQw8eCQHcQAEwhgJ6LLjxcAvlyA) + +--- + +You **can** use `isType` from [type-plus] for one-off assertion functions (especially if you are already using it). + +> Why? + +In many cases, you only need to do type guard for a few specific cases. + +If you are already using [type-plus], +you can use the `isType()` generic type guard so that you don't have to break your flow and add an addition function. + +```ts +const { data } = useQuery(...) + +if (isType(data, v => ...predicate...)) { + // `data` is narrowed to `YourData` +} +``` + +[assertion_functions]: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#assertion-functions +[NodeJS]: https://nodejs.org/ +[type-plus]: https://github.com/unional/type-plus diff --git a/apps/starlight/src/content/docs/typescript-features/assertion_funtion.mdx b/apps/starlight/src/content/docs/typescript-features/assertion_funtion.mdx new file mode 100644 index 00000000..425a648f --- /dev/null +++ b/apps/starlight/src/content/docs/typescript-features/assertion_funtion.mdx @@ -0,0 +1,82 @@ +--- +title: "Assertion Function" +authors: [unional] +tags: [typescript, type-plus] +--- + +[Assertion Functions][assertion_functions] are special functions that asserts certain conditions of your program. + +It is introduced in TypeScript 3.7. + +They throw an error if the condition is not met, and return nothing otherwise. + +Furthermore, the *assertion signature* provides additional information to the compiler, +so that the type can be narrowed down. + +Here is a simple example: + +```ts +function assertIsString(value: unknown): asserts value is string { + if (typeof value !== "string") { + throw new TypeError("value must be a string"); + } +} +``` + +--- + +You **can** throw any type of error. +i.e. you **can** throw error other than `AssertionError`. + +> Why? + +While `AssertionError` may work a little better with test runner, +it is [NodeJS] specific. + +Meaning your code cannot be used in other environments without polyfills. + +--- + +You **can** use `assertType` from [type-plus] for one-off assertion functions (especially if you are already using it). + +> Why? + +In many cases, you only need to do type assertion for a few specific cases. + +If you are already using [type-plus], +you can use the `assertType()` generic assertion function so that you don't have to break your flow and add an addition function. + +```ts +const { data } = useQuery(...) + +assertType(data, v => ...predicate...) + +// `data` is narrowed to `YourData` +``` + +It also has additional assertion functions for basic types: + +```ts +assertType.isUndefined(value) +assertType.isNull(value) +assertType.isNumber(value) +assertType.isString(value) +assertType.isBoolean(value) +assertType.isTrue(value) +assertType.isFalse(value) +assertType.isFunction(value) +assertType.isError(value) +assertType.noUndefined(value) +assertType.noNull(value) +assertType.noNumber(value) +assertType.noString(value) +assertType.noBoolean(value) +assertType.noTrue(value) +assertType.noFalse(value) +assertType.noFunction(value) +assertType.noError(value) +``` + +[assertion_functions]: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#assertion-functions +[NodeJS]: https://nodejs.org/ +[type-plus]: https://github.com/unional/type-plus diff --git a/docs/pages/00-updates/README.md b/docs/pages/00-updates/README.md index 25ac0a38..1b432482 100644 --- a/docs/pages/00-updates/README.md +++ b/docs/pages/00-updates/README.md @@ -46,4 +46,4 @@ TypeScript 4.0 has landed on August 20th, 2020. - Tuple Types - Project Reference -- uknown +- unknown diff --git a/github-page/docs/guidelines/documentations/comments.md b/github-page/docs/guidelines/documentations/comments.md index 17ebdaca..6eb28d2d 100644 --- a/github-page/docs/guidelines/documentations/comments.md +++ b/github-page/docs/guidelines/documentations/comments.md @@ -1,7 +1,6 @@ --- slug: comments -title: "Creating rich comments" -authors: [unional] +title: Creating rich comments tags: [comment, documentation, DX] ---