一键导入
consistent-aliases
Use when narrowing doesn't work as expected. Use when using variables for object properties. Use when refinements are lost.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use when narrowing doesn't work as expected. Use when using variables for object properties. Use when refinements are lost.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use when defining global types. Use when augmenting window. Use when typing environment variables. Use when working with build-time constants. Use when configuring type definitions.
Use when migrating JavaScript to TypeScript. Use when gradually adopting TypeScript. Use when working with mixed codebases. Use when converting large projects. Use when teams are learning TypeScript.
Use when writing asynchronous code. Use when tempted to use callbacks. Use when composing multiple async operations.
Use when creating types from example data. Use when types don't match all cases. Use when API responses vary.
Use when writing type annotations on variables. Use when TypeScript can infer the type. Use when code feels cluttered with types.
Use when defining array-like types. Use when tempted to use number as index type. Use when understanding array keys.
| name | consistent-aliases |
| description | Use when narrowing doesn't work as expected. Use when using variables for object properties. Use when refinements are lost. |
If you create an alias, use it consistently.
When you assign an object property to a variable, you create an alias. TypeScript tracks them separately, so narrowing one doesn't narrow the other. Choose one and stick with it.
One alias OR the original - never mix them in the same scope.
Prefer destructuring for consistent naming.
Remember:
interface Polygon {
exterior: Coordinate[];
bbox?: BoundingBox;
}
function isPointInPolygon(polygon: Polygon, pt: Coordinate) {
const box = polygon.bbox; // Created an alias
if (polygon.bbox) { // Narrows polygon.bbox
if (pt.x < box.x[0]) { // box is still possibly undefined!
// ~~~
// 'box' is possibly 'undefined'
}
}
}
The check on polygon.bbox doesn't narrow box.
function isPointInPolygon(polygon: Polygon, pt: Coordinate) {
const box = polygon.bbox;
if (box) { // Check the alias
if (pt.x < box.x[0]) { // Use the alias
// OK - box is narrowed here
}
}
}
Now both the check and usage refer to the same variable.
function isPointInPolygon(polygon: Polygon, pt: Coordinate) {
const { bbox } = polygon; // Same name as property
if (bbox) {
const { x, y } = bbox; // Continue destructuring
if (pt.x < x[0] || pt.x > x[1] || pt.y < y[0] || pt.y > y[1]) {
return false;
}
}
return true;
}
Benefits:
box vs bbox confusion)Aliasing affects runtime behavior:
const { bbox } = polygon;
if (!bbox) {
calculatePolygonBbox(polygon); // Fills in polygon.bbox
// Now polygon.bbox exists, but bbox is still undefined!
}
The alias and original can diverge at runtime.
TypeScript makes a pragmatic choice about function calls:
function expandPolygon(p: Polygon) { /* ... */ }
if (polygon.bbox) {
polygon.bbox // BoundingBox (narrowed)
expandPolygon(polygon);
polygon.bbox // Still BoundingBox (TypeScript trusts you)
// But the function might have set it to undefined!
}
TypeScript assumes functions don't invalidate refinements. This is usually fine but can be wrong.
if (polygon.bbox) {
const bbox = polygon.bbox; // Capture it locally
expandPolygon(polygon);
bbox // Still BoundingBox - local variable is safe
}
Local variables can't be changed by function calls.
function safeExpand(p: Readonly<Polygon>) {
// Can't modify p.bbox
}
if (polygon.bbox) {
safeExpand(polygon);
polygon.bbox // Guaranteed still BoundingBox
}
Readonly parameters prevent mutation concerns.
// Instead of:
const name = person.nickname;
const displayName = name ? name : person.fullName;
// Use:
const displayName = person.nickname ?? person.fullName;
// TypeScript doesn't connect has() and get():
if (map.has(key)) {
const value = map.get(key); // Still T | undefined
}
// Better pattern:
const value = map.get(key);
if (value !== undefined) {
value // T (narrowed)
}
// Or with nullish coalescing:
const value = map.get(key) ?? defaultValue;
Pressure: "Sometimes I use the property, sometimes the variable"
Response: Pick one. Mixing them breaks narrowing.
Action: Use destructuring for consistent naming.
Pressure: "I know expandPolygon doesn't touch bbox"
Response: TypeScript can't know that. Document with Readonly.
Action: Use local variables or readonly parameters for safety.
if check| Excuse | Reality |
|---|---|
| "The alias is the same thing" | TypeScript tracks them separately |
| "I already checked the property" | Check doesn't narrow the alias |
| "Functions won't mutate it" | TypeScript can't verify that |
// DON'T: Mix alias and original
const box = polygon.bbox;
if (polygon.bbox) { // Checks original
box.x; // Uses alias - still possibly undefined!
}
// DO: Use alias consistently
const box = polygon.bbox;
if (box) { // Checks alias
box.x; // Uses alias - narrowed correctly
}
// DO: Use destructuring
const { bbox } = polygon;
if (bbox) {
const { x, y } = bbox;
}
Choose one name and use it consistently.
When you alias a property, TypeScript tracks the alias and original separately. Narrowing one doesn't narrow the other. Use destructuring for consistent naming, and prefer local variables when function calls might invalidate refinements.
Based on "Effective TypeScript" by Dan Vanderkam, Item 23: Be Consistent in Your Use of Aliases.