You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用TSLint规则禁用TypeScript可索引类型改用Record类型

Hey there! Let's tackle your problem of enforcing Record types instead of indexable object types in TSLint.

First off, let's get this clear: TSLint doesn't have a built-in dedicated rule to directly detect and replace indexable types like { [key: string]: string } with Record<string, string>. Your idea to use the ban-types rule is totally reasonable, but regex configurations for this can be tricky—let's work through the issues and solid solutions:

一、 Fix the ban-types regex configuration

The escape errors or failed detection you ran into are almost certainly from the regex not properly matching TypeScript's indexable type syntax. Try this configuration in your tslint.yml to target string-indexed types:

rules:
  ban-types:
    - true
    - name: "{ [key: string]: * }"
      message: "Please use Record<string, T> instead of indexable types"
      regex: "^\\{\\s*\\[\\s*key\\s*:\\s*string\\s*\\]\\s*:\\s*.+\\s*\\}$"

This regex handles:

  • Escaping curly braces and brackets (since they're special characters in both YAML and regex)
  • Accommodating spaces in index signatures (works for both [key:string] and [key: string] formats)
  • Matching any value type (via the .+ segment)

If your code uses index variable names other than key (like prop or field), swap key in the regex with \\w+ to match any identifier:

regex: "^\\{\\s*\\[\\s*\\w+\\s*:\\s*string\\s*\\]\\s*:\\s*.+\\s*\\}$"

That said, ban-types has clear limitations: it only matches rigidly formatted types. It won't handle nested indexable types, number-indexed types (like { [key: number]: T }), or mixed types with additional properties (e.g., { id: number; [key: string]: string }).

二、 A more robust solution: Custom TSLint rule

If ban-types isn't flexible enough, writing a custom TSLint rule is the way to go. Using TSLint's API and TypeScript's type checker, you can precisely identify all indexable types:

  1. Traverse the AST to find all IndexSignatureDeclaration nodes (the index signature itself)
  2. Check if the node belongs to an object type literal (TypeLiteralNode)
  3. Throw a lint error when detected, prompting a switch to Record

Here's a simplified version of the rule code to reference:

import * as Lint from "tslint";
import * as ts from "typescript";

export class Rule extends Lint.Rules.AbstractRule {
  public static FAILURE_STRING = "Use Record<K, T> instead of indexable object types";

  public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
    return this.applyWithWalker(new IndexSignatureWalker(sourceFile, this.getOptions()));
  }
}

class IndexSignatureWalker extends Lint.RuleWalker {
  public visitIndexSignature(node: ts.IndexSignatureDeclaration) {
    // Verify the index signature is part of an object type literal
    if (ts.isTypeLiteralNode(node.parent)) {
      this.addFailureAtNode(node, Rule.FAILURE_STRING);
    }
    super.visitIndexSignature(node);
  }
}

This rule catches all index signatures (string or number indexed, with any variable name) reliably, which is way more consistent than regex matching.

三、 Bonus tip: Consider migrating to ESLint

One last note: TSLint is officially deprecated, and the TypeScript team now recommends ESLint + the @typescript-eslint plugin. If you plan to maintain your project long-term, migrating to ESLint lets you use similar logic—either configure @typescript-eslint/ban-types with a regex, or write a custom ESLint rule to achieve the same detection.

内容的提问来源于stack exchange,提问作者Tiu Wee Han

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 12:03:12