mcpField
N
narrow-any-scope

narrow-any-scope

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

关于 narrow-any-scope

面向 TypeScript 开发者的编码技能,说明如何在必须使用 `any` 时限制其影响范围,避免类型安全问题扩散。适用于处理无类型依赖、复杂类型错误和代码审查。

主要功能

  1. 01缩小赋值中的 `any` 范围
  2. 02使用内联 `any` 断言
  3. 03标注函数返回类型
  4. 04用带类型变量约束值
  5. 05采用精确的回调签名

适用场景

  1. 01处理无类型的第三方代码
  2. 02将 JavaScript 迁移到 TypeScript
  3. 03审查使用 `any` 的代码

安装

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

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

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

详细介绍

尽可能缩小 any 类型的作用域

概述

如果必须使用 any,就要控制影响范围。

any 会传染——它会在代码中扩散。尽可能缩小它的作用域,以限制其对类型安全的影响。

何时使用此技能

  • 因某些原因不得不使用 any
  • 处理未类型化的第三方代码
  • 处理复杂的类型错误
  • 将 JavaScript 迁移到 TypeScript
  • 审查使用 any 的代码

铁律

NEVER let any escape its minimal necessary scope.

没有例外:

  • 不能因为“这只是一个变量”
  • 不能因为“我之后会修复”
  • 不能因为“这个函数很短”

检测:“any 外溢”的迹象

如果 any 的作用域还能进一步缩小,就缩小它的作用域。

// ❌ VIOLATION: any on parameter escapes to return value
function processExpression(expression: any) {
  const result = expression.evaluate();  // result is any
  return result;                          // Returns any - spreads everywhere
}

// ✅ BETTER: any only where needed
function processExpression(expression: any) {
  const result: number = expression.evaluate();  // Constrain immediately
  return result;                                  // Returns number
}

技巧 1:在赋值时缩小作用域

// ❌ BAD: any spreads
const config = getConfig() as any;
config.debug = true;      // config stays any
const debug = config.debug;  // debug is any

// ✅ GOOD: Constrain immediately
const config = getConfig() as any;
const debug: boolean = config.debug;  // debug is boolean

技巧 2:内联 any 类型断言

// ❌ BAD: any on the whole object
function processObject(obj: any) {
  obj.x = 1;
  obj.y = 2;
  return obj;  // Returns any
}

// ✅ GOOD: any only on the problematic line
function processObject(obj: Foo) {
  // @ts-expect-error - The library typings are wrong here
  (obj as any).secretMethod();
  return obj;  // Returns Foo
}

技巧 3:返回类型注解

// ❌ BAD: Return type infected by any
function parse(input: string) {
  const parsed = JSON.parse(input);  // parsed is any
  return parsed;                      // Return type is any
}

// ✅ GOOD: Explicit return type blocks the any
function parse(input: string): ParsedData {
  const parsed = JSON.parse(input);  // Still any internally
  return parsed;                      // But return type is ParsedData
}

技巧 4:使用中间变量

// ❌ BAD: any infects the whole expression
function calculate(a: number, b: any, c: number) {
  return a + b + c;  // Result is any because b is any
}

// ✅ BETTER: Convert any before use
function calculate(a: number, b: any, c: number) {
  const bNum: number = b;  // Constrain b to number
  return a + bNum + c;     // Result is number
}

技巧 5:使用类型断言,而非 any 参数

// ❌ BAD: Changing parameter type to any
function processUser(user: any) {
  return user.name.toUpperCase();
}

// ✅ GOOD: Keep the type, assert where needed
function processUser(user: User) {
  // Only use any assertion if absolutely necessary
  return (user as any).secretField;  // any is inline only
}

any[] 陷阱

// ❌ DANGEROUS: any[] elements are any
function getFirst(arr: any[]) {
  return arr[0];  // Returns any
}

// ✅ SAFER: Use generics or unknown
function getFirst<T>(arr: T[]): T {
  return arr[0];  // Returns T
}

function getFirst(arr: unknown[]): unknown {
  return arr[0];  // Returns unknown - forces checking
}

函数签名:让 any 更精确

// ❌ BAD: Maximally broad any
type Callback = any;

// ✅ BETTER: Precise function types
type Callback0 = () => any;           // No params
type Callback1 = (arg: any) => any;   // One param
type CallbackN = (...args: any[]) => any;  // Any params

抵御压力指南

1. “就这一个地方”

压力:“any 反正是隔离的”

**回应:**any 会通过返回类型、赋值和函数调用扩散。

**行动:**缩小其作用域。立即添加类型约束。

2. “类型太复杂了”

压力:“我搞不清正确的类型”

**回应:**可以暂时使用 any,但要约束输出。

**行动:**添加显式返回类型。添加中间类型注解。

3. “这是内部代码”

压力:“没有外部代码会用到它”

**回应:**未来的你就是外部代码。

**行动:**缩小 any 的作用域。说明使用它的原因。

危险信号——停止并重新考虑

  • 函数参数使用 any
  • 函数返回 any(尤其是没有显式返回类型时)
  • any 被赋给一个会多次使用的变量
  • any 在表达式中扩散
  • 多个函数之间传递 any

常见的自我辩解(都不成立)

借口事实
“它是隔离的”any 会通过返回和赋值扩散。
“只用一次”这就是一个漏洞的开端。
“我之后会修复”之后永远不会到来。现在就缩小作用域。
“这个函数很短”短函数也可能让 any 扩散。

快速参考

any 的使用场景缩小作用域的技巧
any 参数添加返回类型注解
any 返回值添加显式返回类型
表达式中的 any赋值给有类型的变量
来自 JSON.parse 的 any添加返回类型或进行验证
来自库的 any断言为特定类型

审查 any 的用法

// Before: any everywhere
function process(data: any): any {
  const x = data.foo;        // any
  const y = data.bar;        // any
  return { x, y };           // any
}

// After: any contained
function process(data: any): Result {
  const x: number = data.foo;   // number
  const y: string = data.bar;   // string
  return { x, y };              // Result
}

核心要点

把 any 当作危险物质处理。控制泄漏。

如果必须使用 any,就将它用于尽可能小的一段代码。添加类型注解,阻止它扩散。目标是除了那一行确实需要 any 的代码外,其他所有地方都保持类型安全。

参考资料

基于 Dan Vanderkam 的《Effective TypeScript》,第 43 条:尽可能缩小 any 类型的作用域。

评论

支持 Markdown