mcpField
T
typescript-master

typescript-master

github.com/tomlord1122开发043 次安装6 周前更新
代码仓库

关于 typescript-master

typescript-master 是一项面向 TypeScript 类型系统问题的 skill,适用于设计类型、排查类型错误及处理泛型和类型推断。它以分步方法分析上下文,并涵盖类型收窄、高级类型模式和类型检查脚本。

主要功能

  1. 01分类类型设计与错误问题
  2. 02分析 tsconfig 和项目约束
  3. 03应用泛型与条件类型模式
  4. 04使用类型守卫进行类型收窄
  5. 05提供类型测试与检查脚本

适用场景

  1. 01设计可复用的类型安全泛型
  2. 02诊断类型不匹配或推断问题
  3. 03检查 TypeScript 项目的严格类型设置

安装

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

$npx skills add https://github.com/tomlord1122/tomtom-skill --skill typescript-master

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

附带文件scripts/type-check.sh

详细介绍

TypeScript 语言专家

精通 TypeScript 类型系统的专家助手,涵盖泛型、条件类型、映射类型、类型推断和高级模式。

思考过程

激活后,请遵循以下结构化思路来解决 TypeScript 类型难题:

步骤 1:问题分类

目标: 理解这属于哪类 TypeScript 难题。

需要提出的关键问题:

  • 这是类型设计问题吗?(创建新类型、建模数据)
  • 这是类型错误问题吗?(调试、修复类型不匹配)
  • 这是类型推断问题吗?(泛型、条件类型)
  • 这是类型安全问题吗?(运行时验证、类型收窄)
  • 这是库类型问题吗?(第三方类型、声明文件)

决策点: 对问题进行分类,以选择合适的方法:

  • 类型设计 → 专注于正确建模领域
  • 类型错误 → 追踪类型不匹配的来源
  • 类型推断 → 设计泛型和约束
  • 类型安全 → 使用类型守卫添加运行时验证
  • 库类型 → 检查 @types 包,创建声明
步骤 2:上下文分析

目标: 理解 TypeScript 环境和约束条件。

需要提出的关键问题:

  • 使用的是哪个 TypeScript 版本?(5.0+ 提供了新特性)
  • 严格程度如何?(strict、noUncheckedIndexedAccess 等)
  • 使用哪种模块系统?(ESM、CommonJS、bundler)
  • 是否有现成的类型模式可供遵循?

操作:

  1. 检查 tsconfig.json 中的编译器选项
  2. 在 package.json 中确认 TypeScript 版本
  3. 查看代码库中现有的类型模式

特定版本的功能:

功能最低版本
泛型2.0
条件类型2.8
模板字面量类型4.1
const 类型参数5.0
satisfies 运算符4.9
步骤 3:类型设计原则

目标: 在解决方案中采用 TypeScript 最佳实践。

思考框架——核心原则:

  1. 优先依赖推断,而非注解

    • 尽可能让 TypeScript 进行类型推断
    • 为公共 API 的函数参数和返回类型添加注解
    • 使用 satisfies 进行检查,同时避免类型扩大
  2. 优先使用 unknown,而非 any

    • 使用前,unknown 会强制进行类型检查
    • any 会禁用所有类型检查
    • 例外:确实需要动态类型的场景(很少见)
  3. 使用可辨识联合表示变体

    • 使用字面量类型作为辨识符
    • 支持穷尽性检查
    • 代码可自我说明
  4. 收窄类型,不要扩大

    • 字面量类型优先使用 as const
    • 使用类型守卫收窄类型
    • 避免不必要的类型断言

类型设计问题:

  • “能描述这种情况的最精简类型是什么?”
  • “TypeScript 能推断出类型吗?还是必须添加注解?”
  • “这个联合类型是否已穷尽?”
步骤 4:错误诊断

目标: 系统地诊断类型错误。

思考框架:

  • “TypeScript 期望的是什么,实际收到的又是什么?”
  • “意外的类型是从哪里产生的?”
  • “这是结构性不匹配,还是名义性不匹配?”

常见错误模式:

错误模式可能原因解决方案
Type 'X' is not assignable to 'Y'缺少属性或类型错误添加缺失的属性,修正类型
Property does not exist可选属性或联合类型成员错误添加类型守卫,检查可选属性
Type 'X' has no call signatures不是函数类型检查函数类型
Argument not assignable to 'never'联合类型已穷尽,但未处理所有情况添加缺失的分支处理器

调试策略:

  1. 将鼠标悬停在变量上,查看推断出的类型
  2. 追溯类型被赋值的位置
  3. 检查是否存在隐式 any(启用 noImplicitAny)
  4. 暂时使用 // @ts-expect-error 隔离问题
步骤 5:泛型类型设计

目标: 设计可复用且类型安全的泛型函数和类型。

思考框架:

  • “哪些类型信息会流经此函数?”
  • “类型参数需要哪些约束?”
  • “我能否推断出比当前更多的信息?”

泛型设计模式:

模式用例示例
恒等泛型保留输入类型<T>(x: T) => T
受约束泛型限定为子集<T extends object>
映射类型转换所有属性{ [K in keyof T]: ... }
条件类型在类型层面进行分支T extends U ? X : Y
Infer 关键字提取嵌套类型T extends Promise<infer U> ? U : T

泛型最佳实践:

  • 为参数取有意义的名称(使用 TItem,不要只用 T)
  • 添加能说明意图的约束
  • 在适当时提供默认值(<T = string>)
  • 使用边界情况进行测试(空数组、undefined 等)
步骤 6:类型收窄策略

目标: 安全地收窄类型,以用于运行时操作。

思考框架:

  • “我如何在运行时确定这是类型 X?”
  • “最可靠的检查方式是什么?”
  • “这种收窄方式对 TypeScript 有效吗?”

收窄技术:

技术最适合示例
typeof原始类型typeof x === 'string'
instanceof类实例x instanceof Date
in 运算符属性是否存在'name' in x
判别属性带标签的联合类型x.type === 'success'
自定义类型守卫复杂对象function isUser(x): x is User
断言函数无效时抛出异常asserts x is User

类型守卫模式:

function isUser(obj: unknown): obj is User {
  return (
    typeof obj === 'object' &&
    obj !== null &&
    'id' in obj &&
    'name' in obj &&
    typeof (obj as User).id === 'string'
  );
}
步骤 7:高级类型模式

目标: 在复杂场景中应用高级模式。

思考框架:

  • “是否有可以实现此功能的工具类型?”
  • “我能否组合现有类型?”
  • “这种类型是否易读且易于维护?”

高级模式:

模式用途
模板字面量类型在类型层面进行字符串操作
递归类型树结构、嵌套对象
品牌类型为原始类型实现名义类型
构建器模式类型累积类型信息

品牌类型示例:

type UserId = string & { readonly __brand: unique symbol };

function createUserId(id: string): UserId {
  return id as UserId;
}

function fetchUser(id: UserId) { /* ... */ }

// Type error: string is not UserId
fetchUser("abc"); // Error!
fetchUser(createUserId("abc")); // OK
步骤 8:验证和测试

目标: 确保类型正确且易于维护。

类型测试策略:

  1. 使用 @ts-expect-error 测试无效代码会报错
  2. 创建带断言的类型测试文件
  3. 使用 Expect<Equal<A, B>> 工具类型进行类型断言

类型测试模式:

// Type tests (no runtime code)
type cases = [
  Expect<Equal<ReturnType<typeof fn>, string>>,
  Expect<Equal<Parameters<typeof fn>, [number, string]>>,
];

// Compile-time assertion utility
type Expect<T extends true> = T;
type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends
  (<T>() => T extends Y ? 1 : 2) ? true : false;

可维护性检查清单:

  • 类型已使用 JSDoc 编写文档
  • 复杂类型已拆分为更小的部分
  • 类型名称具有描述性
  • 导出的类型有明确的文档说明

用法

运行类型检查
bash /mnt/skills/user/typescript-master/scripts/type-check.sh [project-dir] [strict-mode]

参数:

  • project-dir - 项目目录(默认:当前目录)
  • strict-mode - 启用严格检查:true/false(默认:true)

示例:

bash /mnt/skills/user/typescript-master/scripts/type-check.sh
bash /mnt/skills/user/typescript-master/scripts/type-check.sh ./my-project
bash /mnt/skills/user/typescript-master/scripts/type-check.sh ./my-project false

检查项:

  • TypeScript 编译(noEmit)
  • 严格类型检查
  • 未使用的变量/导入
  • tsconfig 建议

文档资源

官方文档:

  • TypeScript 手册:https://www.typescriptlang.org/docs/handbook/
  • Type Challenges:https://github.com/type-challenges/type-challenges

类型系统基础

工具类型
// Built-in utilities
type Partial<T> = { [P in keyof T]?: T[P] };
type Required<T> = { [P in keyof T]-?: T[P] };
type Readonly<T> = { readonly [P in keyof T]: T[P] };
type Pick<T, K extends keyof T> = { [P in K]: T[P] };
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
type Record<K extends keyof any, T> = { [P in K]: T };
自定义工具类型
// Deep Partial
type DeepPartial<T> = {
  [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};

// Strict Omit (only known keys)
type StrictOmit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;

// Make specific keys required
type RequireKeys<T, K extends keyof T> = T & Required<Pick<T, K>>;

// Nullable
type Nullable<T> = T | null;

泛型模式

受约束泛型
// Key constraint
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

// Type constraint
function merge<T extends object, U extends object>(a: T, b: U): T & U {
  return { ...a, ...b };
}
使用 infer 进行推断
// Extract return type
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

// Extract promise value
type Awaited<T> = T extends Promise<infer U> ? Awaited<U> : T;

// Extract array element
type ArrayElement<T> = T extends (infer E)[] ? E : never;

// Extract function parameters
type Parameters<T> = T extends (...args: infer P) => any ? P : never;

条件类型

基本条件类型
type IsString<T> = T extends string ? true : false;
type IsArray<T> = T extends any[] ? true : false;
分布式条件类型
// Distributes over union
type ToArray<T> = T extends any ? T[] : never;
type Result = ToArray<string | number>; // string[] | number[]

// Prevent distribution
type ToArrayNonDist<T> = [T] extends [any] ? T[] : never;
type Result2 = ToArrayNonDist<string | number>; // (string | number)[]

可辨识联合类型

type Result<T, E = Error> =
  | { success: true; data: T }
  | { success: false; error: E };

function handleResult<T>(result: Result<T>): T | null {
  if (result.success) {
    return result.data; // TypeScript knows data exists
  } else {
    console.error(result.error); // TypeScript knows error exists
    return null;
  }
}

类型守卫

// Custom type guard
function isUser(obj: unknown): obj is User {
  return (
    typeof obj === 'object' &&
    obj !== null &&
    'id' in obj &&
    'name' in obj &&
    typeof (obj as User).id === 'string'
  );
}

// Assertion function
function assertNonNull<T>(
  value: T,
  message?: string
): asserts value is NonNullable<T> {
  if (value === null || value === undefined) {
    throw new Error(message ?? 'Value is null or undefined');
  }
}

模板字面量类型

type EventName = 'click' | 'focus' | 'blur';
type Handler = `on${Capitalize<EventName>}`;
// "onClick" | "onFocus" | "onBlur"

type PropKey<T extends string> = `get${Capitalize<T>}` | `set${Capitalize<T>}`;
type NameProps = PropKey<'name'>; // "getName" | "setName"

推荐的 tsconfig

{
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "noPropertyAccessFromIndexSignature": true,
    "moduleResolution": "bundler",
    "verbatimModuleSyntax": true
  }
}

向用户展示结果

提供 TypeScript 解决方案时:

  • 优先使用类型推断,而非显式注解
  • 使用 unknown 代替 any
  • 利用可辨识联合类型
  • 提供类型测试示例
  • 说明 TypeScript 版本特性(5.0+:const 类型参数)

故障排除

“类型 'X' 不能赋值给类型 'Y'”

  • 检查是否缺少属性
  • 确认空值处理方式
  • 检查字面量类型与拓宽类型

“类型上不存在该属性”

  • 访问前添加类型守卫
  • 检查该属性是否为可选属性
  • 确认联合类型收窄

“类型复杂度过高”

  • 拆分为更小的类型
  • 使用中间类型别名
  • 考虑简化泛型

评论

支持 Markdown