关于 different-variables-types
这项 TypeScript 技能建议开发者为不同概念使用独立变量,而不是复用变量名或用联合类型放宽类型。重点是表达意图、简化类型并改善推断。
主要功能
- 01每个用途使用独立变量
- 02避免为无关值使用联合类型
- 03尽可能优先使用 const
- 04按含义命名变量
- 05区分类型缩窄与扩宽
适用场景
- 01解决重新赋值导致的类型错误
- 02分开保存类型不同的值
- 03简化使用联合类型的代码
- 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