typescript-variables

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Variables

变量

Apply the TypeScript Style Guide's variable conventions in the context of the current task.
在当前任务的上下文中应用 TypeScript Style Guide 的变量约定。

Workflow

工作流

  1. Inspect the consuming repository's conventions and configuration.
  2. Let explicit repository conventions take precedence over this opinionated guidance.
  3. Apply, review, or explain only the guidance relevant to the task.
  4. State important tradeoffs when the appropriate choice depends on context or judgment.
  1. 检查当前任务所使用仓库的约定和配置。
  2. 仓库中明确的约定应优先于这套带有主观倾向的指导原则。
  3. 仅应用、审查或解释与任务相关的指导原则。
  4. 如果恰当的选择取决于具体上下文或判断,应说明重要的取舍。

Boundaries

边界

  • Keep TypeScript and ESLint responsible for checks they can enforce automatically.
  • Do not introduce unrelated TypeScript Style Guide conventions merely because this skill is active.
  • 让 TypeScript 和 ESLint 负责它们能够自动执行的检查。
  • 不要仅因为启用了此 skill,就引入无关的 TypeScript Style Guide 约定。

Related Guidance

相关指导

Application State

应用状态

For detailed guidance on states that require different data, use
typescript-discriminated-unions
when it is available.
<!-- BEGIN CANONICAL GUIDE CONTENT -->
对于需要不同数据的状态的详细指导,如果
typescript-discriminated-unions
可用,请使用它。
<!-- BEGIN CANONICAL GUIDE CONTENT -->

Variables

变量

Const Assertion

Const Assertion

Strive to declare constants using the const assertion
as const
:
Constants are used to represent values that are not meant to change, ensuring reliability and consistency in a codebase. Const assertions preserve literal types and infer readonly properties.
  • Type Narrowing - Using
    as const
    ensures that literal values (e.g., numbers, strings) are treated as exact values instead of generalized types like
    number
    or
    string
    .
  • Readonly Properties - Objects and arrays get readonly properties, so TypeScript catches direct mutations.
Examples:
  • Objects
    ts
    // ❌ Avoid
    const FOO_LOCATION = { x: 50, y: 130 }; // Type { x: number; y: number; }
    FOO_LOCATION.x = 10;
    
    // ✅ Use
    const FOO_LOCATION = { x: 50, y: 130 } as const; // Type '{ readonly x: 50; readonly y: 130; }'
    FOO_LOCATION.x = 10; // Error
  • Arrays
    ts
    // ❌ Avoid
    const BAR_LOCATION = [50, 130]; // Type number[]
    BAR_LOCATION.push(10);
    
    // ✅ Use
    const BAR_LOCATION = [50, 130] as const; // Type 'readonly [50, 130]'
    BAR_LOCATION.push(10); // Error
  • Template Literals
    ts
    // ❌ Avoid
    const RATE_LIMIT = 25;
    const RATE_LIMIT_MESSAGE = `Max number of requests/min is ${RATE_LIMIT}.`; // Type string
    
    // ✅ Use
    const RATE_LIMIT = 25;
    const RATE_LIMIT_MESSAGE = `Max number of requests/min is ${RATE_LIMIT}.` as const; // Type 'Max number of requests/min is 25.'
应尽量使用 Const Assertion
as const
声明常量:
常量用于表示不应改变的值,从而确保代码库的可靠性与一致性。Const Assertion 可以保留字面量类型,并推断出只读属性。
  • 类型收窄(Type Narrowing) - 使用
    as const
    可确保字面量值(例如数字、字符串)被视为精确值,而不是
    number
    或
    string
    等泛化类型。
  • 只读属性(Readonly Properties) - 对象和数组会获得只读属性,因此 TypeScript 可以捕获直接修改操作。
示例:
  • 对象
    ts
    // ❌ Avoid
    const FOO_LOCATION = { x: 50, y: 130 }; // Type { x: number; y: number; }
    FOO_LOCATION.x = 10;
    
    // ✅ Use
    const FOO_LOCATION = { x: 50, y: 130 } as const; // Type '{ readonly x: 50; readonly y: 130; }'
    FOO_LOCATION.x = 10; // Error
  • 数组
    ts
    // ❌ Avoid
    const BAR_LOCATION = [50, 130]; // Type number[]
    BAR_LOCATION.push(10);
    
    // ✅ Use
    const BAR_LOCATION = [50, 130] as const; // Type 'readonly [50, 130]'
    BAR_LOCATION.push(10); // Error
  • 模板字面量
    ts
    // ❌ Avoid
    const RATE_LIMIT = 25;
    const RATE_LIMIT_MESSAGE = `Max number of requests/min is ${RATE_LIMIT}.`; // Type string
    
    // ✅ Use
    const RATE_LIMIT = 25;
    const RATE_LIMIT_MESSAGE = `Max number of requests/min is ${RATE_LIMIT}.` as const; // Type 'Max number of requests/min is 25.'

Enums & Const Assertion

Enums 与 Const Assertion

Enums are discouraged in the TypeScript ecosystem due to their runtime cost and quirks.
The TypeScript documentation outlines several pitfalls, and TypeScript 5.8 introduced the --erasableSyntaxOnly flag to disable runtime-generating features like enums altogether.
<Rule href="https://eslint.org/docs/latest/rules/no-restricted-syntax">{
'no-restricted-syntax': [     'error',     {       selector: 'TSEnumDeclaration',       message: 'Replace enum with a literal type or a const assertion.',     }, ]
}</Rule>
As a rule of thumb, prefer:
  • Literal types whenever possible.
  • Const assertion arrays when looping through values.
  • Const assertion objects when enumerating arbitrary values.
Examples:
  • Use literal types to avoid runtime objects and reduce bundle size.
    ts
    // ❌ Avoid using enums as they increase the bundle size
    enum UserRole {
      GUEST = 'guest',
      MODERATOR = 'moderator',
      ADMINISTRATOR = 'administrator',
    }
    
    // Transpiled JavaScript
    ('use strict');
    var UserRole;
    (function (UserRole) {
      UserRole['GUEST'] = 'guest';
      UserRole['MODERATOR'] = 'moderator';
      UserRole['ADMINISTRATOR'] = 'administrator';
    })(UserRole || (UserRole = {}));
    
    // ✅ Use literal types - Types are stripped during transpilation
    type UserRole = 'guest' | 'moderator' | 'administrator';
    
    const isGuest = (role: UserRole) => role === 'guest';
  • Use const assertion arrays when looping through values.
    tsx
    // ❌ Avoid using enums
    enum USER_ROLES {
      guest = 'guest',
      moderator = 'moderator',
      administrator = 'administrator',
    }
    
    // ✅ Use const assertions arrays
    const USER_ROLES = ['guest', 'moderator', 'administrator'] as const;
    type UserRole = (typeof USER_ROLES)[number];
    
    const seedDatabase = () => {
      USER_ROLES.forEach((role) => {
        db.roles.insert(role);
      }
    }
    const insert = (role: UserRole) => {...
    
    const UsersRoleList = () => {
      return (
        <div>
          {USER_ROLES.map((role) => (
            <Item key={role} role={role} />
          ))}
        </div>
      );
    };
    const Item = ({ role }: { role: UserRole }) => {...
  • Use const assertion objects when enumerating arbitrary values.
    ts
    // ❌ Avoid using enums
    enum COLORS {
      primary = '#B33930',
      secondary = '#113A5C',
      brand = '#9C0E7D',
    }
    
    // ✅ Use const assertions objects
    const COLORS = {
      primary: '#B33930',
      secondary: '#113A5C',
      brand: '#9C0E7D',
    } as const;
    
    type Colors = typeof COLORS;
    type ColorKey = keyof Colors; // Type "primary" | "secondary" | "brand"
    type ColorValue = Colors[ColorKey]; // Type "#B33930" | "#113A5C" | "#9C0E7D"
    
    const setColor = (color: ColorValue) => {...
    
    setColor(COLORS.primary);
    setColor('#B33930');
由于 enum 存在运行时开销和特殊行为,因此在 TypeScript 生态系统中不推荐使用 enum。
TypeScript 文档列出了若干陷阱,TypeScript 5.8 还引入了 --erasableSyntaxOnly 选项,以完全禁用 enum 等会在运行时生成代码的功能。
<Rule href="https://eslint.org/docs/latest/rules/no-restricted-syntax">{'no-restricted-syntax': [ 'error', { selector: 'TSEnumDeclaration', message: 'Replace enum with a literal type or a const assertion.', }, ]}</Rule>
经验法则如下:
  • 尽可能使用字面量类型。
  • 遍历值时使用 Const Assertion 数组。
  • 枚举任意值时使用 Const Assertion 对象。
示例:
  • 使用字面量类型可避免运行时对象并减小 bundle 体积。
    ts
    // ❌ Avoid using enums as they increase the bundle size
    enum UserRole {
      GUEST = 'guest',
      MODERATOR = 'moderator',
      ADMINISTRATOR = 'administrator',
    }
    
    // Transpiled JavaScript
    ('use strict');
    var UserRole;
    (function (UserRole) {
      UserRole['GUEST'] = 'guest';
      UserRole['MODERATOR'] = 'moderator';
      UserRole['ADMINISTRATOR'] = 'administrator';
    })(UserRole || (UserRole = {}));
    
    // ✅ Use literal types - Types are stripped during transpilation
    type UserRole = 'guest' | 'moderator' | 'administrator';
    
    const isGuest = (role: UserRole) => role === 'guest';
  • 遍历值时使用 Const Assertion 数组。
    tsx
    // ❌ Avoid using enums
    enum USER_ROLES {
      guest = 'guest',
      moderator = 'moderator',
      administrator = 'administrator',
    }
    
    // ✅ Use const assertions arrays
    const USER_ROLES = ['guest', 'moderator', 'administrator'] as const;
    type UserRole = (typeof USER_ROLES)[number];
    
    const seedDatabase = () => {
      USER_ROLES.forEach((role) => {
        db.roles.insert(role);
      });
    }
    const insert = (role: UserRole) => {...
    
    const UsersRoleList = () => {
      return (
        <div>
          {USER_ROLES.map((role) => (
            <Item key={role} role={role} />
          ))}
        </div>
      );
    };
    const Item = ({ role }: { role: UserRole }) => {...
  • 枚举任意值时使用 Const Assertion 对象。
    ts
    // ❌ Avoid using enums
    enum COLORS {
      primary = '#B33930',
      secondary = '#113A5C',
      brand = '#9C0E7D',
    }
    
    // ✅ Use const assertions objects
    const COLORS = {
      primary: '#B33930',
      secondary: '#113A5C',
      brand: '#9C0E7D',
    } as const;
    
    type Colors = typeof COLORS;
    type ColorKey = keyof Colors; // Type "primary" | "secondary" | "brand"
    type ColorValue = Colors[ColorKey]; // Type "#B33930" | "#113A5C" | "#9C0E7D"
    
    const setColor = (color: ColorValue) => {...
    
    setColor(COLORS.primary);
    setColor('#B33930');

Type Union & Boolean Flags

Type Union 与 Boolean Flags

Embrace type unions, especially when type union options are mutually exclusive, instead multiple boolean flag variables.
Boolean flags have a tendency to accumulate over time, leading to confusing and error-prone code, since they hide the actual app state.
ts
// ❌ Avoid introducing multiple boolean flag variables
const isPending, isProcessing, isConfirmed, isExpired;

// ✅ Use type union variable
type UserStatus = 'pending' | 'processing' | 'confirmed' | 'expired';
const userStatus: UserStatus;
Use a literal union when only the state value changes. When each state requires different data, use a discriminated union to represent the valid states explicitly.
应采用 Type Union,尤其是在 Type Union 的选项互斥时,而不是使用多个 Boolean Flag 变量。
Boolean Flag 往往会随着时间不断累积,导致代码混乱且容易出错,因为它们隐藏了应用的实际状态。
ts
// ❌ Avoid introducing multiple boolean flag variables
const isPending, isProcessing, isConfirmed, isExpired;

// ✅ Use type union variable
type UserStatus = 'pending' | 'processing' | 'confirmed' | 'expired';
const userStatus: UserStatus;
当仅状态值发生变化时,使用字面量联合类型(literal union)。当每个状态需要不同数据时,使用 discriminated union(可辨识联合类型) 来明确表示有效状态。

Null & Undefined

Null 与 Undefined

With
strictNullChecks
,
null
and
undefined
have distinct types and meanings. Use them consistently based on what absence means in the application.
Strive to:
  • Use
    null
    when a value is explicitly empty, such as an assignment or function return value.
  • Use
    undefined
    when a value is missing or omitted, such as an optional field in a form, request payload, or database query (Prisma differentiation).
<!-- END CANONICAL GUIDE CONTENT -->
在
strictNullChecks
下,
null
和
undefined
具有不同的类型和含义。应根据“缺失”在应用中的具体含义,一致地使用它们。
应尽量:
  • 当值明确为空时使用
    null
    ,例如赋值或函数返回值。
  • 当值缺失或被省略时使用
    undefined
    ,例如表单、请求载荷或数据库查询中的可选字段(Prisma 对 null 与 undefined 的区分)。
<!-- END CANONICAL GUIDE CONTENT -->