mcpField
L
limit-any-type

limit-any-type

github.com/marius-townhouse开发648 次安装39 周前更新
代码仓库

关于 limit-any-type

这项 TypeScript 技能说明随意使用 `any` 的风险,并介绍 `unknown` 和具体类型等替代方案。它面向补充类型、迁移 JavaScript 代码,以及处理库或 API 数据的开发者。

主要功能

  1. 01说明 `any` 的风险
  2. 02用 `unknown` 表示未知值
  3. 03建议定义具体接口与类型别名
  4. 04识别常见的绕过类型检查做法
  5. 05指导 API 数据的类型设计

适用场景

  1. 01替换为消除报错而使用的 `any`
  2. 02为迁移中的 JavaScript 添加类型
  3. 03描述来自 API 或库的数据

安装

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

$npx skills add https://github.com/marius-townhouse/effective-typescript-skills --skill limit-any-type

安装后在 Claude Code 中输入/limit-any-type确认已加载。

详细介绍

限制 any 类型的使用

概述

any 类型实际上会禁用 TypeScript 对使用它的代码进行类型检查。

虽然 any 可以作为应急手段,但它会消除 TypeScript 的优势:类型安全、开发体验、重构信心和预防 Bug。

何时使用此技能

  • 想用 any 来消除类型错误
  • 将 JavaScript 代码迁移到 TypeScript
  • 使用没有类型定义的第三方库
  • 因复杂的类型错误而感到沮丧
  • 为现有代码添加类型注解

铁律

NEVER use any without a specific, documented reason.

没有例外:

  • 不能因为“只是快速修复一下”
  • 不能因为“类型太复杂了”
  • 不能因为“以后再修”
  • 不能因为“运行时能正常工作”

检测:“any 异味”

如果你要写 any,先停下来问:“有没有更好的办法?”

// ❌ VIOLATION: Using any because it's "easy"
function processData(data: any) {
  return data.items.map((item: any) => item.name);
}

// ✅ CORRECT: Define proper types
interface DataItem {
  name: string;
}
interface Data {
  items: DataItem[];
}
function processData(data: Data) {
  return data.items.map(item => item.name);
}

any 的五大危害

1. 没有类型安全
let age: number;
age = '12' as any;  // No error, but wrong!
age += 1;           // "121" at runtime
2. 破坏约定
function calculateAge(birthDate: Date): number { /* ... */ }

let birthDate: any = '1990-01-19';  // string, not Date!
calculateAge(birthDate);  // No error, but will fail
3. 缺少语言服务
// With proper types: autocomplete, refactoring, documentation
person.  // Shows: name, age, email...

// With any: nothing
(person as any).  // No autocomplete
4. 掩盖重构 Bug
interface Props {
  onSelectItem: (id: number) => void;  // Changed from (item: any)
}

function handleSelectItem(item: any) {
  selectedId = item.id;  // Bug! Should be just `item` now
}
5. 隐藏类型设计问题
// ❌ BAD: What is this state?
const appState: any = { /* ... */ };

// ✅ GOOD: Clear, documented design
interface AppState {
  user: User | null;
  preferences: UserPreferences;
  isLoading: boolean;
}

抵御压力的原则

1. “太复杂了”

压力:“这个类型太复杂了,用 any 更简单。”

**回应:**复杂的类型往往意味着复杂的数据。定义类型会迫使你理解并记录数据模型。

**行动:**拆分类型。使用接口和类型别名。问问自己:“这些数据实际是什么样的?”

2. “以后再修”

压力:“我之后会回来补上合适的类型。”

**回应:**你不会的。技术债务会不断累积。any 会在代码库中蔓延。

**行动:**现在就修复。如果确实做不到,就添加带有工单号的 // TODO。

3. “这个库没有类型定义”

压力:“这个 npm 包没有 @types。”

**回应:**你有其他选择:编写最精简的类型、使用 unknown,或者创建 .d.ts 文件。

**行动:**对于你无法控制的值,使用 unknown。针对实际用到的内容创建专用接口。

any 的更好替代方案

不要使用改用
用于未知值的 anyunknown(强制你先收窄类型)
any[]unknown[] 或具体类型
(x: any) => any正确的函数签名
Record<string, any>Record<string, unknown>
用于 JSON 的 any使用 unknown 解析并验证

危险信号——停下来重新考虑

  • 在同一个函数中使用多个 any 类型
  • 用 as any 消除错误
  • 使用 // @ts-ignore 或 @ts-expect-error 绕过检查
  • 在公开 API 签名中使用 any
  • 在函数返回类型中使用 any

常见的自我开脱(都不成立)

借口事实
“运行时能正常工作”类型的作用是在运行前捕获 Bug。
“TypeScript 太严格了”TypeScript 正在保护你。弄清楚它在告诉你什么。
“我不知道类型是什么”使用 unknown 并收窄类型。
“这是第三方库”为你实际用到的内容编写最精简的类型。
“这只是内部代码”内部代码也是代码。以后你还是得调试它。

快速参考

症状行动
不理解的类型错误仔细阅读错误信息,使用 unknown
复杂的嵌套类型拆分成更小的接口
来自 API 的动态数据定义响应类型,在边界处进行验证
从 JS 迁移从 unknown 开始,逐步添加类型

归根结底

每个 any 都是一个随时可能发生的 Bug。

对不了解的值使用 unknown。对已知的值使用合适的类型。必须使用 any 时,将其限制在尽可能小的范围内,说明原因,并计划将其移除。

参考资料

改编自 Dan Vanderkam 的《Effective TypeScript》,第 5 条:限制 any 类型的使用。

评论

支持 Markdown