oxc-project/oxc · warning

Prefer `String#at()` over `String#substring()` when getting…

Error message

Prefer `String#at()` over `String#substring()` when getting one character.

What it means

This is a lint diagnostic from the oxlint rule `unicorn/prefer-at`. It fires when `String#substring()` (or a slice-like call) is used just to fetch a single character, suggesting `String#at()` instead, which is clearer and supports negative indices. The library throws it to modernize character-access code.

Solutions

  1. Replace `s.substring(i, i + 1)` with `s.at(i)` (or `.at(-n)` for offsets from the end).
  2. Apply the rule's auto-fix when available.
  3. Target ES2022+ (or polyfill String.prototype.at) if runtime support for very old environments is required, otherwise disable the rule.

Example fix

// before
const ch = str.substring(i, i + 1);
// after
const ch = str.at(i);
Defensive patterns

Strategy: validation

Validate before calling

// Ensure target supports String#at before adopting the rule
if (!String.prototype.at) { throw new Error('String#at unsupported in this environment'); }

Prevention

When it happens

Trigger: oxlint detects a call to `.substring(...)` on a string where the arguments indicate only one character is being extracted (e.g. `s.substring(i, i+1)` or `s.substring(i, i+1)`-equivalent single-index access), via check_substring -> prefer_at_over_substring_diagnostic.

Common situations: Legacy string-parsing code written before `String#at()` (ES2022) existed; codebases ported from older JS targets; fresh oxlint adoption with the unicorn preset flags old idioms.

Understand the failure class

Background: "is deprecated and will be removed" — deprecation warnings for old API names, keywords, and options, and how to migrate before the removal release — this error's family across 29 libraries.

Related errors


AI-assisted analysis of oxc-project/oxc@12cb547351 (2026-09-20). Data as JSON: /api/errors/3ced1fc712980ec8. Report an issue: GitHub.

Appendix: source

Thrown at crates/oxc_linter/src/rules/unicorn/prefer_at.rs:35

use crate::{
    AstNode,
    ast_util::variable_declaration_kind,
    context::LintContext,
    fixer::{RuleFix, RuleFixer},
    rule::Rule,
    utils::{get_precedence, is_same_expression},
};

fn prefer_at_diagnostic(span: Span, method: &str) -> OxcDiagnostic {
    OxcDiagnostic::warn(format!("Prefer `.at()` over `{method}`."))
        .with_help("Use `.at()` for index access.")
        .with_note("https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/at")
        .with_label(span)
}

fn prefer_at_over_substring_diagnostic(span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn(
        "Prefer `String#at()` over `String#substring()` when getting one character.",
    )
    .with_help("Use `.at()` for index access.")
    .with_label(span)
}

#[derive(Debug, Default, Clone)]
pub struct PreferAt(Box<PreferAtConfig>);

#[derive(Debug, Default, Clone, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase", default, deny_unknown_fields)]
pub struct PreferAtConfig {
    /// Check all index access, not just special patterns like `array.length - 1`.
    /// When enabled, `array[0]`, `array[1]`, etc. will also be flagged.
    check_all_index_access: bool,
    /// List of function names to treat as "get last element" functions.
    /// These functions will be checked for `.at(-1)` usage.
    get_last_element_functions: Vec<String>,

View on GitHub (pinned to 12cb547351)