oxc-project/oxc · warning · OxcDiagnostic
Prefer String#slice() over String#{method_name}()
Error message
Prefer String#slice() over String#{method_name}() What it means
This is the oxlint rule `unicorn/prefer-string-slice`. It flags calls to the legacy substring methods `String#substr(start, length)` (deprecated) and `String#substring(a, b)` (with its argument-swapping and negative-clamping quirks) on receivers the rule can resolve to strings, and recommends `String#slice()`, which has consistent index semantics everywhere.
Source
Thrown at crates/oxc_linter/src/rules/unicorn/prefer_string_slice.rs:12
use oxc_ast::{
AstKind,
ast::{Argument, Expression, MemberExpression},
};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::Span;
use crate::{AstNode, context::LintContext, rule::Rule};
fn prefer_string_slice_diagnostic(span: Span, method_name: &str) -> OxcDiagnostic {
OxcDiagnostic::warn(format!("Prefer String#slice() over String#{method_name}()"))
.with_label(span)
}
#[derive(Debug, Default, Clone)]
pub struct PreferStringSlice;
declare_oxc_lint!(
/// ### What it does
///
/// Prefer [`String#slice()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/slice) over [`String#substr()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/substr) and [`String#substring()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/substring).
///
/// ### Why is this bad?
///
/// [`String#substr()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/substr) and [`String#substring()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/substring) are the two lesser known legacy ways to slice a string. It's better to use [`String#slice()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/slice) as it's a more popular option with clearer behavior that has a consistent [`Array` counterpart](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice).
///
/// ### Examples
///
/// Examples of **incorrect** code for this rule:View on GitHub (pinned to e1e7af627c)
Solutions
- Rewrite `str.substr(start, len)` as `str.slice(start, start + len)`.
- Rewrite `str.substring(a, b)` as `str.slice(a, b)` — but only after confirming `a <= b` and neither argument is negative (otherwise semantics differ).
- Run `oxlint --fix` where a fixer applies, and hand-review each conversion for the negative/swap cases.
- Disable with `"unicorn/prefer-string-slice": "off"` if you are maintaining a legacy codebase deliberately matched to old behavior.
Example fix
// before const tail = s.substring(1); const head = s.substr(0, 3); // after const tail = s.slice(1); const head = s.slice(0, 3);
Defensive patterns
Strategy: validation
Validate before calling
// Standardize on slice for all substring extraction const head = s.slice(0, 3); const tail = s.slice(-3); // CI: npx oxlint --deny-warn unicorn/prefer-string-slice src/
Prevention
- Never write `substring` with possibly-reversed or negative indices; `slice` handles both predictably.
- Convert `substr(start, len)` manually — length must become `start + len`.
- Grep for `substr(` and `substring(` during dependency upgrades; they are deprecation magnets.
When it happens
Trigger: `str.substr(0, 5)`, `str.substring(1, 4)`, or `str.substring(4)` on a receiver recognized as a string (via member-expression checks in the rule's `run`). Computed receivers or optional chains are skipped.
Common situations: Porting old JS/jQuery-era code or snippets copied from MDN legacy examples; the real hazard is `substring`'s behavior of swapping arguments when `a > b` and treating negatives as 0, which differs from every other language — reviewers ask for `slice` to remove the footgun. Note `substr`'s second argument is a length, not an end index, so converting requires arithmetic.
Related errors
- `String.raw` should be used to avoid escaping `\`.
- This pattern can be replaced with `{replacement}`.
- Prefer `String#replaceAll()` over `String#replace()` when us
- Prefer String#startsWith over a regex with a caret.
- Prefer String#endsWith over a regex with a dollar sign.
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/c9a4d7457d440e7a.
Report an issue: GitHub.