关于 typescript
为编写或修改代码的开发者提供 TypeScript 5+ 约定,强调通过类型建模、严格检查和清晰的包边界提升代码可靠性。
主要功能
- 01品牌类型与判别联合
- 02优先使用 `satisfies` 和常量对象
- 03避免 `any` 并隔离类型断言
- 04类型导入与内部类型推断
- 05声明文件与项目引用
- 06严格 tsconfig 与模块解析
适用场景
- 01设计领域类型与状态处理
- 02审查 TypeScript 代码变更
- 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