mcpField
A
avoid-unnecessary-type-params

avoid-unnecessary-type-params

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

关于 avoid-unnecessary-type-params

面向审查泛型函数和类型的 TypeScript 开发者的技能。它说明多余的类型参数会增加复杂度、妨碍推断,并可能带来没有类型关系支撑的安全假象。

主要功能

  1. 01识别仅使用一次的类型参数
  2. 02解释泛型建立类型关系的规则
  3. 03建议对弱类型输入使用 unknown
  4. 04简化泛型函数签名
  5. 05检查泛型是否改善类型推断

适用场景

  1. 01审查泛型 API 签名
  2. 02排查类型推断不佳的问题
  3. 03减少代码中的多余泛型

安装

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

$npx skills add https://github.com/marius-townhouse/effective-typescript-skills --skill avoid-unnecessary-type-params

安装后在 Claude Code 中输入/avoid-unnecessary-type-params确认已加载。

详细介绍

避免不必要的类型参数

概述

“泛型黄金法则”指出,类型参数应在函数签名中出现两次或更多次。如果类型参数只出现一次,它就没有关联任何内容,很可能是不必要的。不必要的类型参数会制造类型安全的假象,还可能降低类型推断的效果。

本技能可帮助你识别并消除多余的类型参数,从而编写更简洁、更易维护的代码,让 TypeScript 能更有效地进行类型推断。

何时使用此技能

  • 编写泛型函数或类型
  • 检查类型签名是否清晰
  • 类型参数(除声明处外)只出现一次
  • 想添加泛型来增加“灵活性”
  • 调试不理想的类型推断

铁律

类型参数必须出现两次或更多次,才能建立关联。如果类型参数只出现一次,请认真考虑是否真的需要它。

检测

留意以下模式:

// RED FLAGS - Unnecessary type parameters
function parseYAML<T>(input: string): T;  // Return-only generic
type Fn = <T>(x: T) => void;  // T only used once
function third<A, B, C>(a: A, b: B, c: C): C;  // A and B appear once
function getLength<T extends Lengthy>(x: T): number;  // T only in parameter

黄金法则

类型参数用于关联类型。如果类型参数只出现一次,它就没有关联任何内容:

// GOOD: T appears twice, relating input and output
function identity<T>(arg: T): T {
  return arg;
}

// BAD: T only appears once (in return type)
function parseYAML<T>(input: string): T;
// Equivalent to: function parseYAML(input: string): any

// Usage shows the problem:
const data: User = parseYAML('...');  // Looks safe, but T can be anything
const bad: Banana = parseYAML('...');  // Also "valid" - no error!

仅用于返回值的泛型

仅用于返回值的泛型很危险,因为它们等同于没有显式 as 的类型断言:

// BAD: Return-only generic
declare function parseYAML<T>(input: string): T;
const user: User = parseYAML('...');  // No error, but no validation either

// GOOD: Return unknown, force explicit assertion
declare function parseYAML(input: string): unknown;
const user = parseYAML('...') as User;  // Explicit about the assertion

// Or use validation:
const user = parseYAML('...');
if (isUser(user)) {  // Type guard
  // user is User here
}

简化不必要的泛型

// BEFORE: Unnecessary type parameters
function third<A, B, C>(a: A, b: B, c: C): C {
  return c;
}

// AFTER: Only keep C which appears twice
function third<C>(a: unknown, b: unknown, c: C): C {
  return c;
}

何时需要泛型

// GOOD: K appears twice, relating parameter to return type
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

// K appears in: parameter type (key: K) and return type (T[K])
// This IS a good use of generics

类泛型

// GOOD: T appears multiple times, relating class properties
class Container<T> {
  private items: T[] = [];
  add(item: T): void { this.items.push(item); }
  getAll(): T[] { return this.items; }
}

// BAD: T only used in one method
class Joiner<T extends string | number> {
  join(els: T[]): string {
    return els.map(String).join(',');
  }
}
// Better: Move T to method or use concrete type
class Joiner {
  join(els: (string | number)[]): string {
    return els.map(String).join(',');
  }
}
// Best: Just a function
function join(els: (string | number)[]): string {
  return els.map(String).join(',');
}

抵御压力的准则

当有人施压要求添加“灵活”的泛型时:

  1. 统计出现次数:类型参数是否出现了两次或更多次?
  2. 检查关联关系:它是否关联了多个值的类型?
  3. 考虑 unknown:unknown 是否同样适用?
  4. 测试类型推断:泛型能改善还是损害类型推断?

危险信号

反模式不好的原因
function f<T>(): T仅用于返回值,不具备类型安全性
type Fn = <T>(x: T) => voidT 未用于返回值,因此不必要
单次使用类型的泛型增加复杂度,却没有带来好处
T extends X,其中 T 只出现一次约束没有帮助

常见的自我辩解

“这样能让 API 更灵活”

事实:不必要的泛型会制造安全的假象。它们不会带来真正的灵活性,只会造成困惑。

“以后会用到”

事实:需要时再添加泛型,不要提前添加。之后随时可以添加。

“看起来更专业”

事实:简单、正确的类型比复杂且不必要的类型更专业。

快速参考

模式结论修正方式
function f<T>(x: T): T✓ 良好T 关联输入与输出
function f<T>(x: string): T✗ 不好使用 unknown 或具体类型
function f<T>(x: T): void✗ 不好使用 unknown 或 any
class C<T> { method(x: T): T }✓ 良好T 关联了多处用法
class C<T> { method(x: T): void }✗ 不好将 T 移到方法上,或移除

总结

泛型的第一条规则就是“不要用”。只有当类型参数能在类型之间建立关联时才添加它。如果类型参数只出现一次,就将其移除。这样能让代码更简洁,并改善类型推断。

参考资料

  • Dan Vanderkam 著《Effective TypeScript》,第 2 版
  • 条目 51:避免不必要的类型参数

评论

支持 Markdown