mcpField
D
different-variables-types

different-variables-types

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

关于 different-variables-types

这项 TypeScript 技能建议开发者为不同概念使用独立变量,而不是复用变量名或用联合类型放宽类型。重点是表达意图、简化类型并改善推断。

主要功能

  1. 01每个用途使用独立变量
  2. 02避免为无关值使用联合类型
  3. 03尽可能优先使用 const
  4. 04按含义命名变量
  5. 05区分类型缩窄与扩宽

适用场景

  1. 01解决重新赋值导致的类型错误
  2. 02分开保存类型不同的值
  3. 03简化使用联合类型的代码
  4. 04明确被复用为临时结果的变量含义

安装

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

$npx skills add https://github.com/marius-townhouse/effective-typescript-skills --skill different-variables-types

安装后在 Claude Code 中输入/different-variables-types确认已加载。

详细介绍

为不同类型使用不同变量

概述

不要将同一个变量用于不同目的。

在 JavaScript 中,你可以将任何值赋给任何变量。但在 TypeScript 中,变量的类型通常是固定的。为不同概念使用不同变量可以提高类型安全性,让代码更清晰。

何时使用此技能

  • 将同一个变量名用于不同目的
  • 为变量赋予不同类型的值
  • 仅为适应重新赋值而使用联合类型
  • 排查因复用变量而导致的类型错误

铁律

One variable, one type, one purpose.
Different concepts deserve different names.

请记住:

  • 变量的值可以改变;类型通常不会改变
  • 联合类型比简单类型更难处理
  • const 优于 let
  • 不同的名称传达不同的意图

检测:复用变量导致的类型错误

let productId = "12-34-56";
fetchProduct(productId);  // Expects string

productId = 123456;
// ~~~~~~~ Type 'number' is not assignable to type 'string'

fetchProductBySerialNumber(productId);
// Expects number

TypeScript 会根据第一次赋值,将 productId 推断为 string。

联合类型“修复方案”(有问题)

// Works, but creates problems
let productId: string | number = "12-34-56";
fetchProduct(productId);

productId = 123456;  // OK
fetchProductBySerialNumber(productId);  // OK

// But now everywhere you use productId, you need type guards:
if (typeof productId === 'string') {
  // ...
}

联合类型更难处理,也会模糊代码的意图。

更好的方案:使用不同变量

const productId = "12-34-56";
fetchProduct(productId);

const serial = 123456;
fetchProductBySerialNumber(serial);

优点:

  • 将无关概念分开
  • 变量名更具体
  • 类型推断更好(无需注解)
  • 类型更简单(不是联合类型)
  • 变量可以是 const

为什么 const 更好

// let: type can be reassigned
let x = 'hello';
x = 'goodbye';  // OK
x = 42;         // Error: different type

// const: value cannot change
const y = 'hello';
y = 'goodbye';  // Error: cannot reassign const
// No type ambiguity ever

const 让代码更容易被人和 TypeScript 理解。

变量遮蔽:另一个问题

const productId = "12-34-56";
fetchProduct(productId);

{
  const productId = 123456;  // Different variable, same name
  fetchProductBySerialNumber(productId);
}

这样可行,因为它们是在不同作用域中的不同变量。但这会让人困惑——最好改用不同的名称。

类型收窄与变量复用

TypeScript 支持类型收窄(让类型变得更具体):

let x: string | number = getValue();

if (typeof x === 'string') {
  x  // Type: string (narrowed)
  x.toUpperCase();  // OK
}

这与尝试扩宽类型(让类型变得不那么具体)不同;后者行不通:

let x = 'hello';  // Type: string
x = 42;  // Error: can't widen to string | number

真实示例

// Bad: reusing 'result' for different things
let result = await fetchUser(id);
processUser(result);

result = await fetchPosts(id);  // Error: different type!
processPosts(result);

// Good: descriptive names for each
const user = await fetchUser(id);
processUser(user);

const posts = await fetchPosts(id);
processPosts(posts);

抵制压力的准则

1. “我想复用这个变量”

压力:“这只是临时用一下,我会重新给它赋值。”

**回应:**使用新变量。这样更清晰,也能确保类型安全。

**行动:**创建一个名称明确的新 const。

2. “联合类型也能用”

压力:“我直接用 string | number 就行。”

**回应:**每次使用该变量时,联合类型都会增加复杂性。

**行动:**将变量拆开并使用简单类型,会更容易处理。

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

  • 使用 let x: A | B,而 A 和 B 用于不同目的
  • 变量被重新赋值为完全不同的值
  • 重新赋值导致类型错误
  • temp 或 result 等通用变量名被重复使用

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

借口事实
“这样能少用一个变量”变量成本低;Bug 代价高
“数据相同,只是格式不同”格式不同 = 变量不同
“代码更少”清晰度更重要 > 代码更少

快速参考

// DON'T: Reuse variable for different purposes
let id = "abc";
fetchByString(id);
id = 123;  // Error

// DON'T: Use union just to allow reassignment
let id: string | number = "abc";

// DO: Different variables for different concepts
const stringId = "abc";
const numericId = 123;

总结

不同的概念值得使用不同的变量。

TypeScript 的类型不会改变(类型收窄除外)。使用不同变量实现不同目的。这样代码会更清晰、类型更简单,Bug 也会更少。

参考资料

基于 Dan Vanderkam 的《Effective TypeScript》第 19 条:为不同类型使用不同变量。

评论

支持 Markdown