typescript

typescript

熱門

LobeHub TypeScript 程式码风格与型别安全指南。适用于编辑 TS/TSX/MTS、修复型别、选择 interface 或 type、避免使用 any/object、处理 import type、非同步流程或使用 ts-expect-error 时。

8.1萬星標
1.6萬分支
更新於 2026/7/30
SKILL.md
唯讀
名稱
typescript
描述

LobeHub TypeScript 程式码风格与型别安全指南。适用于编辑 TS/TSX/MTS、修复型别、选择 interface 或 type、避免使用 any/object、处理 import type、非同步流程或使用 ts-expect-error 时。

TypeScript 程式码风格指南

型别与型别安全

  • 当 TypeScript 能自动推导型别时,避免加上显式的型别标注
  • 避免隐式 any;必要时应显式指定型别
  • 使用精确的型别:优先使用 Record<PropertyKey, unknown>,而非 objectany
  • 定义物件结构(例如 React props)时优先使用 interface;联合型别(unions)与交集型别(intersections)则使用 type
  • 优先使用 as const satisfies XyzInterface,而非单纯的 as const
  • 优先顺位:@ts-expect-error > @ts-ignore > as any
  • 避免无意义的 null/undefined 参数;设计严谨的函式契约(function contracts)
  • 优先使用 ES 模组扩充(declare module '...')而非 namespace;切勿引入基于 namespace 的扩展模式
  • 当型别需要具备扩充性时,在源头型别处暴露出一个可合并的精简 interface,让各个功能/外挂(plugin)在本地自行扩充,而不是把所有扩充栏位集中管理在单一 registry 档案中
  • 针对套件区域(package-local)的扩充模式(如 PipelineContext.metadata),请将元资料(metadata)栏位直接定义在读取或写入该栏位的 processor/provider/plugin 旁

非同步模式

  • 优先使用 async/await,而非回呼函式(callbacks)或 .then() 链式呼叫
  • IO 优先采用非同步(Async-first):新的 IO 程式码(fs、child_process 等)在其边界处必须使用非同步 API——预设应使用基于 Promise 的变体(如 import { readFile } from 'fs/promises'),切勿预设使用 *Sync。函式色彩(Function coloring)具有不对称性:我们永远不需要将 async 迁移为 sync,但 sync 转换为 async(当 IO 变慢、增加并发量、或演变成子进程/网路呼叫时)会强迫重构上游链条上的每一个呼叫端——这是会不断滚雪球的「同步优先」技术债。非同步的微小开销(线程池分发、快取竞态)不能作为理由:竞态条件应透过快取 Promise 本身而非快取结果来解决
  • *Sync 仅允许在一种特殊情况下使用:呼叫位置被锁定在不受你控制的同步契约内——即既有的同步签名链(修复 bug 时无需非理性地重构旧有同步链,但新的独立模组绝对不能继续延长此类链条),或是仅支援同步的回呼函式(如 process.on('exit'))。模组载入阶段(Module-load-time)与 CLI 启动初始化并非例外——在这些场景请使用顶层 await(ESM)
  • 在安全的前提下,使用 Promise.allPromise.race 进行并发操作

汇入(Imports)

  • 本项目使用 simple-import-sort/importsconsistent-type-importsfixStyle: 'separate-type-imports'

  • 独立型别汇入:仅用于型别的汇入请一律使用 import type { ... },切勿使用 import { type ... } 的行内语法

  • 当档案中已经有来自某个套件的 import type { ... },而你需要新增数值(value)汇入时,请将它们保持为两条独立的叙述句

    import type { ChatTopicBotContext } from '@lobechat/types';
    import { RequestTrigger } from '@lobechat/types';
    
  • 在每个 import 叙述句内部,修饰符(specifiers)需按名称英文字母顺序排序

程式码结构

  • 优先使用物件解构
  • 使用一致且具描述性的命名;避免使用晦涩难懂的缩写
  • 将魔术数字/字串替换为命名良好的常数
  • 将程式码格式化交由自动工具处理
  • 优先使用具名导出(named exports),而非 export default——这能让重构改名与 IDE 自动汇入保持同步,并避免使用 import Foo from './foo' 时产生的名称偏离。仅在框架有明确规定时保留 export default(如 Next.js 的 page/route/layout、React.lazy 的目标元件,或像 vitest.config.ts 这类设定档)。程式码库中仍存有许多 export default——这属于历史遗留债务,并非值得效仿的模式;在上述框架要求的例外之外,撰写新程式码时切勿模仿既有的 export default 用法
  • 在为常见的防护检查/解析/规范化(如 record 检查、字串提取、空字串处理、时间辅助函式、JSON 安全工具等)新增本地辅助函式前,请先搜寻 packages/utils。若该辅助函式已存在或明显属于该目录,请直接从 @lobechat/utils(或对应的 @lobechat/utils/* 子路径)汇入,避免在各个功能档案中重复编写微小的辅助函式。

UI 与主题

  • 使用 @lobehub/ui 及 Ant Design 元件,而非原始 HTML 标记
  • 针对深色模式与行动装置响应式进行设计
  • 使用 antd-style 的 Token 系统,而非硬编码的色彩

效能

  • 仅从资料库查询所需的栏位

可复用性

  • 复用 packages/utils 中已有的工具函式或已安装的 npm 套件
  • 切勿手写可复用的 record/object-map 防护检查(例如 typeof value === 'object' && value !== null);请直接从 @lobechat/utils/object 汇入辅助函式,如 isRecordisPlainRecordisObjectLiketoRecordpickStringUnknownRecord 等。
  • Date.now() 赋值给常数一次并重复使用,以保持一致性

记录(Logging)

  • 切勿记录使用者的隐私资讯(如 API Key 等)
  • 不要直接使用 import { log } from 'debug'(会印出至 console)
  • 在 catch 区块中使用 console.error,而非 debug 套件
  • 务必在 .catch() 回呼中记录错误——静默捕捉的 .catch(() => fallback) 会吞掉失败讯息,导致无法除错