From 32c924af752508d210af6773f9bb4e53624d79ab Mon Sep 17 00:00:00 2001 From: Maxwell Date: Tue, 3 Dec 2024 23:24:17 -0800 Subject: [PATCH] feat: two post about ts and js --- posts/ts_and_js_best_practise_01_zh.md | 158 +++++++++++++++++ posts/ts_and_js_best_practise_02_zh.md | 236 +++++++++++++++++++++++++ 2 files changed, 394 insertions(+) create mode 100644 posts/ts_and_js_best_practise_01_zh.md create mode 100644 posts/ts_and_js_best_practise_02_zh.md diff --git a/posts/ts_and_js_best_practise_01_zh.md b/posts/ts_and_js_best_practise_01_zh.md new file mode 100644 index 0000000..fb4f90e --- /dev/null +++ b/posts/ts_and_js_best_practise_01_zh.md @@ -0,0 +1,158 @@ +--- +title: JavaScript 和 TypeScript 最佳实践 +published_at: 2024-11-29T15:00:00.000Z +snippet: 这篇文章作者详细介绍了不少 JS 和 TS 中的最佳实践, 非常实用。 +--- + +## JavaScript 和 TypeScript 核心概念 + +### 4 个基础特性 + +1. **原始类型(Primitives)** + + - 原始类型包括 5 种传统类型:`null`、`undefined`、`boolean`、`number`、`string`,以及新增的两种类型:`symbol` 和 `bigint`。 + - **重点**: + - `symbol` 主要用于创建对象的唯一键,避免键值冲突。 + - 类型强制(Coercion):当调用原始类型的函数时,JavaScript 会用其对象包装器(如 `Boolean`、`Number`)包装原始值,从而实现调用。 + +2. **函数(Functions)** + + - **创建方式**: + - 函数声明:`function functionName() {}` + - 箭头函数:`() => {}` + - 对象字面量中的方法:`{ key: function() {} }` + - 类方法:`class MyClass { myMethod() {} }` + - **最佳实践**: + - 在顶层使用函数声明以利用提升(Hoisting)。 + - 在嵌套函数中使用箭头函数。 + - 单参数箭头函数省略括号:`val => val * 2`。 + +3. **对象(Objects)** + + - **创建方式**: + - 对象字面量:`{ key: value }` + - 使用 `new` 调用构造函数:`new Date()` + - 类实例化:`class MyClass {}`。 + - **对象字面量**:更适合组织数据和代码,避免使用类的复杂性。 + - **类**: + - 通常避免用类来处理 IO 数据或作为项目结构的核心。 + - 适合动态数据和需要封装逻辑的场景,例如数据结构(如 `Map`)。 + - **建议**: + - 对于 IO 数据,使用接口(`interface`)定义数据结构,使用对象字面量组织相关方法。 + +4. **类型(Types)** + - **定义方式**: + - 类型别名:`type MyType = ...` + - 接口:`interface MyInterface { ... }` + - **使用场景**: + - 使用类型别名定义联合类型或简单结构。 + - 使用接口定义复杂对象结构。 + +--- + +### 脚本(文件)类型 + +1. **声明型(Declaration)** + + - 导出单个声明,例如枚举或类型:`HttpStatusCodes.ts`。 + +2. **模块型(Modular)** + + - 导出包含相关函数或变量的对象字面量:`UserRepo.ts`。 + +3. **库存型(Inventory)** + + - 存储全局共享的小型声明:`types.ts`。 + +4. **线性型(Linear)** + - 执行一系列命令的文件:`setup-db.ts`。 + +--- + +### 文件组织结构 + +- **推荐顺序**: + + 1. 变量(只读或常量) + 2. 类型 + 3. 运行逻辑(可选,保持短小) + 4. 函数 + 5. 类(仅限小型类,大型类应独立文件) + +- **注意事项**: + - `export default` 始终放在文件末尾。 + - 在线性脚本中,代码可按任务分组,而非按类型组织。 + +--- + +### 何时使用类? + +- **适合场景**: + + - 动态数据需要与方法紧密耦合。 + - 需要封装状态和逻辑,例如数据结构(如 `Map`)。 + - 需要依赖注入,确保在多个地方使用同一实例。 + +- **避免场景**: + - 处理 IO 数据:类实例化时方法不会传递,需额外构造或使用静态方法。 + - 项目核心架构:使用函数式或过程式编程简化项目,不依赖类的状态管理。 + +--- + +### 示例代码 + +#### 函数声明 vs 箭头函数 + +```typescript +function declaredFunction() { + console.log("Function declaration"); +} + +const arrowFunction = (val: number) => val * 2; +``` + +#### 对象字面量与类 + +```typescript +// 对象字面量 +const user = { + name: "John", + sayHello() { + console.log(`Hello, ${this.name}`); + }, +}; + +// 类 +class User { + constructor(public name: string) {} + sayHello() { + console.log(`Hello, ${this.name}`); + } +} +``` + +#### 使用接口和模块化脚本管理数据 + +```typescript +// User.ts +export interface IUser { + name: string; + age: number; +} + +const User = { + isValid(user: IUser): boolean { + return !!user.name && user.age > 0; + }, +}; + +export default User; +``` + +--- + +### 总结 + +- **优先使用函数声明和对象字面量**,简化代码结构。 +- **避免使用类组织项目或处理 IO 数据**,改用接口和模块化脚本。 +- 遵循文件组织规则,确保代码可维护性和清晰性。 diff --git a/posts/ts_and_js_best_practise_02_zh.md b/posts/ts_and_js_best_practise_02_zh.md new file mode 100644 index 0000000..98d94ff --- /dev/null +++ b/posts/ts_and_js_best_practise_02_zh.md @@ -0,0 +1,236 @@ +--- +title: JavaScript 和 TypeScript 最佳实践 +published_at: 2024-12-02T15:00:00.000Z +snippet: 这篇文章作者详细介绍了不少 JS 和 TS 中的最佳实践, 非常实用。 +--- + +## 命名规则 + +### 文件/文件夹 + +1. **文件夹**: + + - 一般用小写加连字符,例如 `shared-utils/`。 + - React 中包含组件的文件夹可用首字母大写,例如 `Home/` 包含 `Home.tsx` 和 `Home.test.tsx`。 + +2. **文件命名**: + - **声明脚本**:文件名应与声明名称匹配,例如导出 `useSetState` 的文件应命名为 `useSetState.ts`。 + - **模块脚本**:使用 PascalCase,例如 `UserRepo.ts`。 + - **库存脚本**:使用小写加连字符,例如 `shared-types.ts`。 + - **线性脚本**:使用小写加连字符,例如 `setup-db.ts`。 + - **辅助测试文件夹**:以双下划线包裹,例如 `__test-helpers__/`。 + +--- + +### 变量命名 + +1. **全局静态变量**: + + - 用大写加下划线(`UPPER_SNAKE_CASE`),例如:`const SALT_ROUNDS = 12;`。 + - 简单的数组或对象(没有嵌套)也用 `UPPER_SNAKE_CASE`。 + +2. **局部变量**: + + - 在函数内部声明的变量使用 `camelCase`。 + - 布尔变量一般以 `is` 开头,例如:`session.isLoggedIn`。 + +3. **相关变量分组**: + - 使用单个声明块定义相关变量,提高代码可读性和性能,但不要过度使用。 + ```typescript + const FOO_BAR = "abc", + MAX_COUNT = 10; + ``` + +--- + +### 函数命名 + +1. **格式**: + + - 一般使用 `camelCase`。 + - JSX 组件使用 `PascalCase`。 + - 函数名应反映动作,使用动词格式,例如 `fetchName()`。 + - 简单的常量返回函数可省略动词: + + ```typescript + const Errors = { + SomeError: "Error message", + EmailNotFound(email: string) { + return `User with email "${email}" not found.`; + }, + } as const; + ``` + +2. **特殊规则**: + - 辅助函数(仅限文件内部使用)用下划线开头,例如:`function _helperFn() {}`。 + - IO 数据返回用 `fetch`,非 IO 数据返回用 `get`,例如: + - `user.getFullName()` + - `UserRepo.fetchUser()`。 + +--- + +### 对象命名 + +1. **不可变对象**: + + - 全局静态对象使用 `UPPER_SNAKE_CASE`。 + - 模块或声明脚本导出的对象使用 `PascalCase`,并用 `as const` 标记为不可变。 + +2. **动态对象**: + - 在函数内部的对象用 `camelCase`。 + - 运行时返回的动态对象也用 `camelCase`。 + +--- + +### 类和枚举 + +1. **类**: + + - 类名用 PascalCase。 + - 类的静态只读变量用 PascalCase,例如 `Dog.Species`。 + - 实例变量和方法用 `camelCase`。 + +2. **枚举**: + - 枚举名和键均用 PascalCase,例如: + ```typescript + enum NodeEnvs { + Dev = "development", + Prod = "production", + } + ``` + +--- + +### 类型和接口 + +1. **类型别名**: + + - 类型名以 `T` 开头,例如:`type TMouseEvent = React.MouseEvent;`。 + +2. **接口**: + - 接口名以 `I` 开头,例如:`interface IUser { name: string; email: string; }`。 + +--- + +### 注释规则 + +1. **函数注释**: + + - 使用 `/** Comment */` 格式,放在函数声明上方,首字母大写并以句号结束。 + + ```typescript + /** + * Add two numbers. + */ + function add(a: number, b: number): number { + return a + b; + } + ``` + +2. **代码块注释**: + + - 在函数内部用 `//` 注释,注释首字母大写并以句号结束。 + +3. **分隔代码块**: + + - 用 `// **** Section Name **** //` 分隔文件的主要部分(变量、类型、函数等)。 + +4. **复杂逻辑注释**: + - 对复杂逻辑分块注释,用 `/** */` 分隔大的功能。 + +--- + +### 导入规则 + +1. **组织导入**: + + - 库在顶部,自己代码在下方。 + - 相同目录的导入放在最底部。 + - 超过字符限制的导入单独换行。 + +2. **示例**: + + ```typescript + import express from "express"; + import { UserRepo } from "@src/repos/UserRepo"; + + import helpers from "./helpers"; + ``` + +--- + +### 示例脚本 + +1. **模块脚本**: + + ```typescript + // MailUtil.ts + const SUPPORT_EMAIL = "support@example.com"; + + /** + * Send an email. + */ + function sendEmail(to: string, subject: string, body: string) { + console.log(`Sending email to ${to}`); + } + + export default { + sendEmail, + } as const; + ``` + +2. **声明脚本**: + + ```typescript + // EnvVars.ts + export default { + PORT: process.env.PORT, + DB_HOST: process.env.DB_HOST, + } as const; + ``` + +3. **线性脚本**: + + ```typescript + // server.ts + import express from "express"; + + const app = express(); + + app.use(middleware); + + export default app; + ``` + +--- + +### 其他代码风格 + +1. **布尔表达式**: + + - 用括号提升可读性: + ```typescript + if ((isFoo && isBar) || isBaz) { + console.log("Condition met."); + } + ``` + +2. **可选链**: + + - 使用 `?.` 替代 `foo && foo.bar`。 + - 使用 `??` 替代 `(str || '')`。 + +3. **长条件语句**: + + - 每行一个逻辑条件,嵌套逻辑缩进。 + ```typescript + if (user?.isActive && (role !== "ADMIN" || permissions?.length > 0)) { + // Do something + } + ``` + +4. **对象参数格式**: + - 对象字面量的花括号放在函数参数同一行: + ```typescript + doSomething("arg1", { key: "value" }, "arg2"); + ```