mcpField
T
typescript

typescript

github.com/alexander-danilenko开发18101 次安装2 周前更新
代码仓库

关于 typescript

为编写或修改代码的开发者提供 TypeScript 5+ 约定,强调通过类型建模、严格检查和清晰的包边界提升代码可靠性。

主要功能

  1. 01品牌类型与判别联合
  2. 02优先使用 `satisfies` 和常量对象
  3. 03避免 `any` 并隔离类型断言
  4. 04类型导入与内部类型推断
  5. 05声明文件与项目引用
  6. 06严格 tsconfig 与模块解析

适用场景

  1. 01设计领域类型与状态处理
  2. 02审查 TypeScript 代码变更
  3. 03设置编译器与模块选项

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/alexander-danilenko/cortex-claude-code-plugins --skill typescript

安装后在 Claude Code 中输入/typescript确认已加载。

详细介绍

TypeScript

TypeScript 5+ 的团队约定。请应用于你编写或修改的代码;除非另有要求,否则不要为了符合约定而重构未触碰的文件。

约定

  • 用类型建模领域,而不是用检查。 品牌类型(type UserId = string & { readonly __brand: 'UserId' })和可辨识联合会在编译时暴露错误,几乎没有成本。运行时防护则会让同样的错误在生产环境中才被发现。
  • 凡是有状态的情况,都使用可辨识联合——请求生命周期、表单状态、解析结果等。这样编译器会强制处理每种状态,新变体出现时也会作为错误暴露出来,而不是被静默跳过。
  • 优先使用 satisfies,而不是 as。 satisfies 会根据类型进行验证,同时保留较窄的推断字面类型;as 则会绕过检查。只有在你掌握了编译器无法得知的信息时才使用 as,并在注释中说明原因。
  • 优先使用常量对象,而不是 enum。 as const 对象是普通值,不会生成代码,也不会带来名义类型上的意外;enum 会生成运行时代码,而 const enum 在 isolatedModules 下会出问题。
  • any 就是错误报告。 使用 unknown 并缩窄类型。如果边界处确实无法避免 any,就将它隔离在一个适配器函数中,别让它扩散到各个调用点。
  • 单独导入类型(import type { … })。打包器会干净地移除这些导入;混合导入可能会让你原本想移除的运行时依赖继续存在。
  • 让类型推断发挥作用。 为导出接口和公共签名添加类型注解,让内部代码自行推断;过度注解只会增加噪声,并逐渐偏离实际类型。
  • 作为库供他人使用的内容都要提供 .d.ts(declaration: true)。否则,使用者会退回到 any,你的类型工作也就止步于包边界。
  • 单体仓库:使用项目引用和 composite。 增量构建只会重新构建发生变化的部分;单一的扁平 tsconfig 则会在每次编辑时重新编译整个项目。

值得展示的两种惯用写法

只有强制检查穷尽性,它才真正成立。联合类型新增变体时,对它执行 switch 仍然可以顺利编译——assertNever 才能让每个需要更新的位置都报出构建错误:

function assertNever(x: never): never {
  throw new Error(`Unhandled variant: ${JSON.stringify(x)}`);
}

function area(s: Shape): number {
  switch (s.kind) {
    case "circle":
      return Math.PI * s.r ** 2;
    case "rect":
      return s.w * s.h;
    default:
      return assertNever(s); // add a variant → compile error here
  }
}

只有在获取品牌类型的唯一途径是经过验证的函数时,品牌才有意义:

type Brand<T, B> = T & { readonly __brand: B };
type Email = Brand<string, "Email">;

export function toEmail(raw: string): Email {
  if (!raw.includes("@")) throw new Error(`Not an email: ${raw}`);
  return raw as Email;
}

构造函数中的 as 是唯一合理的用法——它位于验证边界,将未经验证的值转换为已验证的值。在其他任何地方将值断言为 Email,都会让整个类型设计失去意义。

tsconfig 基线

strict: true 并未启用所有值得开启的选项。请添加以下选项——每个选项都能捕获默认配置集遗漏的一类错误:

{
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "noPropertyAccessFromIndexSignature": true,
    "noImplicitOverride": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "isolatedModules": true,
    "declaration": true,
    "skipLibCheck": true
  }
}

noUncheckedIndexedAccess 是价值最高、也最难采用的选项:它会让 arr[i] 返回 T | undefined,这才符合实际情况。新项目请开启此选项;现有项目则要做好迁移准备。

模块解析:Node 运行输出时使用 NodeNext,由打包器处理时使用 bundler。

评论

支持 Markdown