关于 typescript-ops
typescript-ops 是面向开发者的 TypeScript 技能,涵盖类型系统与生产实践。它结合速查内容和深入指南,并介绍 TypeScript 6、7 的采用注意事项。
主要功能
- 01类型收窄与工具类型参考
- 02泛型、条件类型和映射类型模式
- 03现代 TypeScript 功能指南
- 04TypeScript 6 和 7 迁移说明
- 05tsconfig 与严格模式指南
- 06使用 Zod 4 进行运行时验证
适用场景
- 01为联合类型值选择类型守卫
- 02设计可复用的泛型类型辅助项
- 03检查严格编译器配置
- 04评估迁移到 TypeScript 7
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ 0xdarkmatter/ claude-mods --skill typescript-ops安装后在 Claude Code 中输入/typescript-ops确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
assets/typescript-facts.jsonreferences/config-strict.mdecosystem.mdgenerics-patterns.mdts7-native-compiler.mdtype-system.mdutility-types.mdscripts/check-typescript-facts.pytests/run.sh详细介绍
TypeScript 操作
全面介绍 TypeScript 技能,涵盖类型系统、泛型和生产环境模式。
截至 2026-08-08 验证的生态系统信息(TypeScript 7、Zod 4、Valibot 1)。
时效性检查: python scripts/check-typescript-facts.py --offline 会断言目录中标注版本的事实(TypeScript 主版本、zod、valibot)仍在正文中提及,且上方注明日期的时效性说明仍然存在;运行 --live 可确认每个软件包在 npm 上的主版本仍与文档所述一致。目录:assets/typescript-facts.json。
类型收窄决策树
How to narrow a type?
│
├─ Primitive type check
│ └─ typeof: typeof x === "string"
│
├─ Instance check
│ └─ instanceof: x instanceof Date
│
├─ Property existence
│ └─ in: "email" in user
│
├─ Discriminated union
│ └─ switch on literal field: switch (event.type)
│
├─ Null/undefined check
│ └─ Truthiness: if (x) or if (x != null)
│
├─ Custom logic
│ └─ Type predicate: function isUser(x: unknown): x is User
│
└─ Assertion (you know better than TS)
└─ as: value as string (escape hatch, avoid when possible)
类型守卫示例
interface Dog { bark(): void; breed: string }
interface Cat { meow(): void; color: string }
function isDog(pet: Dog | Cat): pet is Dog {
return "bark" in pet;
}
function handlePet(pet: Dog | Cat) {
if (isDog(pet)) {
pet.bark(); // TS knows it's Dog here
} else {
pet.meow(); // TS knows it's Cat here
}
}
可辨识联合类型
type Result<T> =
| { status: "success"; data: T }
| { status: "error"; error: string }
| { status: "loading" };
function handle<T>(result: Result<T>) {
switch (result.status) {
case "success": return result.data; // data is available
case "error": throw new Error(result.error); // error is available
case "loading": return null;
}
// Exhaustiveness check: result is `never` here
const _exhaustive: never = result;
}
实用类型速查表
| 实用类型 | 功能 | 示例 |
|---|---|---|
Partial<T> | 所有属性均为可选 | Partial<User> 用于更新载荷 |
Required<T> | 所有属性均为必需 | Required<Config> 用于已验证的配置 |
Readonly<T> | 所有属性均为只读 | Readonly<State> 用于不可变状态 |
Pick<T, K> | 选取特定属性 | Pick<User, "id" | "name"> |
Omit<T, K> | 移除特定属性 | Omit<User, "password"> |
Record<K, V> | 键和值均有类型的对象 | Record<string, number> |
Exclude<U, E> | 从联合类型中移除类型 | Exclude<Status, "deleted"> |
Extract<U, E> | 保留联合类型中的类型 | Extract<Event, { type: "click" }> |
NonNullable<T> | 移除 null/undefined | NonNullable<string | null> |
ReturnType<F> | 函数返回类型 | ReturnType<typeof fetchUser> |
Parameters<F> | 将函数参数表示为元组 | Parameters<typeof createUser> |
Awaited<T> | 解包 Promise 类型 | Awaited<Promise<User>> = User |
泛型模式
受约束的泛型
// Basic constraint
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
// Multiple constraints
function merge<T extends object, U extends object>(a: T, b: U): T & U {
return { ...a, ...b };
}
// Default generic type
type ApiResponse<T = unknown> = {
data: T;
status: number;
};
条件类型
// Basic conditional
type IsString<T> = T extends string ? true : false;
// infer keyword - extract inner type
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
type UnwrapArray<T> = T extends (infer U)[] ? U : T;
// Distributive conditional (distributes over union)
type ToArray<T> = T extends any ? T[] : never;
// ToArray<string | number> = string[] | number[]
// Prevent distribution with wrapping
type ToArrayNonDist<T> = [T] extends [any] ? T[] : never;
// ToArrayNonDist<string | number> = (string | number)[]
映射类型
// Make all properties optional and nullable
type Nullable<T> = { [K in keyof T]: T[K] | null };
// Add prefix to keys
type Prefixed<T, P extends string> = {
[K in keyof T as `${P}${Capitalize<string & K>}`]: T[K];
};
// Prefixed<{ name: string }, "get"> = { getName: string }
// Filter keys by value type
type StringKeys<T> = {
[K in keyof T as T[K] extends string ? K : never]: T[K];
};
深入了解:加载 ./references/generics-patterns.md,了解高级类型级编程、递归类型和模板字面量类型。
现代语言特性(TypeScript 5.x → 6.0)
| 特性 | 始于 | 功能 |
|---|---|---|
satisfies 运算符 | 4.9 | 根据类型检查值,但不扩大其类型 |
| 标准(TC39)装饰器 | 5.0 | 无需 experimentalDecorators,即可在类/方法上使用 @decorator |
const 类型参数 | 5.0 | function f<const T>(x: T) 无需在调用处使用 as const,即可推断字面量类型 |
using 声明 | 5.2 | 显式资源管理(Symbol.dispose),退出作用域时自动清理 |
| 推断出的类型谓词 | 5.5 | arr.filter(x => x !== null) 无需手写 x is T 守卫即可收窄类型 |
verbatimModuleSyntax | 5.0 | 强制仅用于类型的导入使用 import type,取代 importsNotUsedAsValues |
// const type parameters (5.0) - literal inference without as const
function routes<const T extends readonly string[]>(paths: T): T { return paths; }
const r = routes(["/home", "/about"]); // readonly ["/home", "/about"], not string[]
// using declarations (5.2) - deterministic cleanup
function readConfig() {
using file = openFile("config.json"); // file[Symbol.dispose]() runs at scope exit
return parse(file.contents);
}
// Inferred type predicates (5.5) - no manual guard needed
const names = ["a", null, "b"].filter(x => x !== null); // string[], not (string | null)[]
TypeScript 6.0(过渡版本)
TS 6.0 是基于 JavaScript 的编译器的最后一个版本。它旨在过渡到 TS 7 中原生(Go)编译器,因此主要变化是更严格、现代化的默认设置:
strict: true为默认值 — 从未设置该选项的 tsconfig 现在会启用完整的严格检查- 默认值现代化:
module: esnext、target: es2025;es2025库提供 Temporal、Map.getOrInsert、RegExp.escape的类型 - 移除旧选项:
moduleResolution: classic;module: amd/umd/system/none;最低target现在为 ES2015(es5已弃用) - 互操作始终启用:无法再禁用
esModuleInterop/allowSyntheticDefaultImports - 新增
--stableTypeOrdering标志,便于对比 6.0 → 7.0 迁移差异
TypeScript 7(当前主版本 — 原生编译器)
TS 7 是用 Go 重写的版本(之前名为 tsgo),自 2026-07-08 起在 npm 上稳定发布。
类型检查语义相同,类型检查速度提升约 8–16 倍——但该软件包仅提供
bin/tsc shim,不含 JavaScript 编译器 API:在 7.0.x 中,require('typescript') 会抛出
MODULE_NOT_FOUND(该 API 将在 7.1+ 中回归)。影响采用决策的因素:
- 使用 TS 程序化 API(
ts.createSourceFile、自定义 lint 脚本、codemod、typescript-eslint)的仓库工具必须不再依赖 AST、改用其他解析器,或固定使用别名 - 对嵌入式语言进行类型检查的工具(vue-tsc、svelte-check、Astro、MDX)在移植到 7.1+ API 之前都固定使用 TS 6——这是选择技术栈时需要考虑的实际因素
- 已使用 TS 6 的 tsconfig 可直接采用默认配置(可跳过 6.0 过渡版本);
baseUrl会导致硬错误(TS5102) - 在 7 旁边运行
typescript5回退别名会导致裸调用npx tsc产生歧义——试运行期间,脚本必须使用明确的编译器路径
深入了解:加载 ./references/ts7-native-compiler.md,了解无 JS API 时的解决方法、
双重安装导致的 bin 歧义、生态系统无法采用情况表、实测采用基准(12.1 倍)
以及是否继续的检查清单。
tsconfig 快速参考
{
"compilerOptions": {
// Strict mode (default in TS 6; state it explicitly anyway)
"strict": true, // Enables all strict checks
"noUncheckedIndexedAccess": true, // arr[0] is T | undefined
// Module system (TS 6 defaults to module: esnext; interop is always on)
"module": "esnext", // or "nodenext" for Node
"moduleResolution": "bundler", // or "nodenext"
// Output (TS 6 defaults target to es2025; min supported is es2015)
"target": "es2022",
"outDir": "dist",
"declaration": true, // Generate .d.ts
"sourceMap": true,
// Paths — tsconfig-relative; don't add baseUrl (TS 7 hard-errors on it, TS5102)
"paths": { "@/*": ["./src/*"] },
// Strictness extras
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}
深入了解:加载 ./references/config-strict.md,了解严格模式迁移、monorepo 配置和项目引用。
常见问题
| 问题 | 原因 | 修复方法 |
|---|---|---|
any 泄漏 | any 会禁用其涉及的所有内容的类型检查 | 改用 unknown 并进行收窄 |
as 断言隐藏错误 | 断言不会在运行时进行检查 | 使用类型守卫或验证(Zod) |
enum 的问题 | 数字枚举不具备类型安全性,反向映射容易造成混淆 | 使用 as const 对象或字符串字面量联合类型 |
object 与 Record、{} 的区别 | {} 匹配任何非 null 值,object 表示非原始类型 | 要表示“任意对象”,请使用 Record<string, unknown> |
| 数组索引访问 | 默认情况下,arr[999] 返回 T 而不是 T | undefined | 启用 noUncheckedIndexedAccess |
| 可选与 undefined | { x?: string } 允许缺少键,{ x: string | undefined } 要求键存在 | 明确选择所需语义 |
! 非空断言 | 会关闭 null 检查,但不影响运行时行为 | 使用 ?? defaultValue 或适当的 null 检查 |
| 结构类型意外之处 | { a: 1, b: 2 } 可赋值给 { a: number } | 使用品牌类型实现名义类型 |
品牌类型 / 名义类型
// Prevent accidentally mixing types that are structurally identical
type UserId = string & { readonly __brand: "UserId" };
type OrderId = string & { readonly __brand: "OrderId" };
function createUserId(id: string): UserId { return id as UserId; }
function getUser(id: UserId) { /* ... */ }
const userId = createUserId("u-123");
const orderId = "o-456" as OrderId;
getUser(userId); // OK
getUser(orderId); // Error: OrderId not assignable to UserId
运行时验证(Zod 4)
import { z } from "zod";
// Define schema (Zod 4: string formats are top-level - z.email(), not z.string().email())
const UserSchema = z.object({
id: z.number(),
name: z.string().min(1),
email: z.email(),
role: z.enum(["admin", "user"]),
settings: z.object({
theme: z.enum(["light", "dark"]).default("light"),
}).optional(),
});
// Infer type from schema
type User = z.infer<typeof UserSchema>;
// Validate
const user = UserSchema.parse(untrustedData); // throws on invalid
const result = UserSchema.safeParse(untrustedData); // returns { success, data/error }
需要了解的 Zod 4 变化(如果你熟悉 Zod 3):字符串格式已移至顶层
(z.email()、z.uuid()、z.url()——z.string().email() 这种方法形式已弃用);
错误定制统一使用单个 error 参数(不再支持 invalid_type_error /
required_error);解析速度更快,并提供可进行 tree-shaking 的 zod/mini 入口点。
参考文件
深入了解特定主题时,可加载以下文件。每个文件均可独立阅读。
| 参考文件 | 加载时机 |
|---|---|
./references/type-system.md | 高级类型、品牌类型、类型级编程、satisfies 运算符 |
./references/generics-patterns.md | 泛型约束、条件类型、映射类型、模板字面量、递归类型 |
./references/utility-types.md | 所有内置实用工具类型及示例、自定义实用工具类型 |
./references/config-strict.md | tsconfig 深入介绍、严格模式迁移、项目引用、monorepo 设置 |
./references/ts7-native-compiler.md | 采用 TS 7 原生(Go)编译器:无 JS API、bin 歧义、生态系统无法采用情况、基准测试与是否继续的决策 |
./references/ecosystem.md | Zod/Valibot、类型安全的 API 客户端、ORM 类型、使用 Vitest 进行测试 |
另请参阅
testing-ops- 跨语言测试策略ci-cd-ops- TypeScript CI 流水线、CI 中的类型检查