Skip to content

RegExp literal flag types #38671

Open
Open

Description

Search Terms

RegExp Regex literal flags as const narrowing

Suggestion

This is similar to the proposal for typing named capture groups #32098
It would be useful to narrow RegExp literals based on their flags as well. This could be modeled as type parameter(s) as in that proposal, or as a type intersection, which I will use here.

const myRegExp = /hello/y; // has type RegExp & {dotAll: false, global: false, ignoreCase: false, multiline: false, sticky: true, unicode: false, flags: 'y'};

Use Cases

Regular expressions have different behavior when defined with different flags, and functions may have different behavior when they receive them, so they may want to distinguish the flags of a RegExp for overloads or allowed argument values.

Examples

In the standard library, String.prototype.match returns either the first match with its capture groups, or a list of all matches, depending on whether the argument is a global RegExp. This could be modeled as an overload:

match(str: string): RegExpMatchArray|null
match(regexp: RegExp & {global: false}): RegExpMatchArray|null
match(regexp: RegExp & {global: true}): Array<string>|null;
match(regexp: RegExp): RegExpMatchArray|null;

I recently wrote some functions which only work with sticky RegExps, so I had to put checks at the top of each function:

function match(regexp: RegExp) {
    if (!regexp.sticky) { throw new Error("Invalid argument -- RegExp must use the /y 'sticky' flag"); }
   ...
}

match(/sticky example/y); // compiles and runs fine
match(/non-sticky example/); // compiles fine, runtime error

I'd like to define the function instead as:

type StickyRegExp = RegExp & {sticky: true};
function match(regexp: StickyRegExp) {
   ...
}

match(/sticky example/y); // compiles and runs fine
match(/non-sticky example/); // compiler error

Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

Activity

  1. webstrand commented on Jun 17, 2021

    @webstrand
    Contributor

    I've implemented the as const modifier for RegExp literals (https://github.com/webstrand/TypeScript/tree/regexp-literal-flags). This does not include support for const foo = /foo/g receiving the type RegExp & { global: true, ignoreCase: false, multiline: false, ... }. Since as const was not previously permitted on RegExp literals, this is not a breaking change.

    I played around with adapting the type-freshness system to include regular expression literals, but it looks like that system was never designed to interact with non-literal types. Changing this would involve either adding regexps as a primitive type or comprehensive changes to the freshness system to allow non-literal types to have fresh types.

    I would be willing to continue to work on this feature, if there's any continuing interest in it? I'll probably need a little guidance, so I don't make a mess of things. It looks like this needs to be added to the backlog, before I can make a pull request.

  2. Tyler-Murphy commented on Sep 20, 2021

    @Tyler-Murphy

    This would also be useful for String.prototype.replaceAll, which throws a runtime error if the first argument is a non-global regular expression. See eslint/eslint#15073 for more context.

  3. codpro2005 commented on Jul 22, 2025

    @codpro2005

    I wrote a custom library ts-regexp that seems to mostly address this issue. That said, it would be cool if this was possible natively, though the heavy compilation may discourage it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Awaiting More FeedbackThis means we'd like to hear from more people who would be helped by this featureSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions