Repository navigation
Open
Labels
Awaiting More FeedbackThis means we'd like to hear from more people who would be helped by this featureThis means we'd like to hear from more people who would be helped by this featureSuggestionAn idea for TypeScriptAn idea for TypeScript
Description
Search Terms
named regexp, named capture groups
Motivation
Currently named capture groups are a bit of a pain in TypeScript:
- All names are of type string even if the regexp doesn't have that named group.
- You need to use non-null assertion for
.groupseven when that is the only possibility.
Suggestion
I propose making RegExp higher order on its named capture groups so that .groups is well typed.
// Would have type: RegExp<{ year: string, month: string }>
const date = /(?<year>[0-9]{4})-(?<month>[0-9]{2})/
const match = someString.match(date)
if (match) {
// match.groups type would be { year: string, month: string }
// currently is undefined | { [key: string]: string }
}
// Would have type RegExp<{ year: string, month?: string }>
const optionalMonth = /(?<year>[0-9]{4})(-(?<month>[0-9]{2}))?/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.
Reacted by Andrii Dieiev, Felix Becker, Wojciech Fiderek, Jessica Franco, kbradl16, Michael Schmidt, Patrick Rebsch, Remy Rylan, Guillaume Camus, Sam Denty and 95 more
Metadata
Metadata
Assignees
Labels
Awaiting More FeedbackThis means we'd like to hear from more people who would be helped by this featureThis means we'd like to hear from more people who would be helped by this featureSuggestionAn idea for TypeScriptAn idea for TypeScript
Activity
fatcerberus commentedon Jun 26, 2019
I could have sworn there was already another ticket discussing this exact issue at length (there were a lot of tradeoffs etc.), but I can’t find it now.
RyanCavanaugh commentedon Jun 26, 2019
There may have been one for group arity?
weswigham commentedon Jun 26, 2019
It would be kinda neat with this to make types like
RegExp</(?<year>[0-9]{4})-(?<month>[0-9]{2})/, { year: /[0-9]{4}/, month: /[0-9]{2}/ }>.fatcerberus commentedon Jun 27, 2019
This sounds like dependent typing to me, which is a rather large can of worms to open.
Jamesernator commentedon Jun 27, 2019
I don't think so. I think it would be as simple as something like:
Note that all of the type information is already encoded in the regular expression literal
/(?<foo>[0-9]+)/implies that.groupsis{ foo: string }if it the match actually exists.EDIT: Fixed code.
nmain commentedon Jun 27, 2019
Might be nice to add the same stronger typing for numbered groups at the same time, so that
Would only have valid indexers
[0],[1], and[2]felixfbecker commentedon Jul 26, 2019
There is an ESLint rules that enforces the use of named capture groups to avoid bugs & improve readability: https://eslint.org/docs/rules/prefer-named-capture-group
Paired with this feature it would be amazing
Jessidhia commentedon Aug 20, 2019
These helper methods kinda smell "any-ish" because of how their generic is used but they should be safer and easier to use than trying to directly read from
.groupsor having to write your own argument handling forString#replace. I'm not sure TypeScript itself will ever be able to have a proper type forString#replacebecause of how... extremely variadic it is; it's probably not impossible with slice types, but it'd require two generics on everyRegExpto be able to know how many capturing groups there are in total (both named and unnamed).There might be no need to copy the numeric captures, though; I just made them be copied because it seemed to make sense to put the matched substring in
0instead of moving to a separate argument.Bessonov commentedon Oct 20, 2019
I've overall problem with RexExp definition and definition of objects and arrays. From my point of view, allowing something like:
Same for arrays, but, well, this one is very surprising:
is a big misconception in sake of convenience. This leads the one of greatest type system ad absurdum. But I'm sure, the core team has another opinion on that, unfortunately.
Based on above statements the definition for RegExpMatch* isn't helpful:
Infer types from regular expression is possible (from my point of view), but very complex. Instead of that I would like to see more developer support to make it type safe (pseudo code):
To make it more type safe:
If developer makes a mistake in typings, well, that's OK. But better as allow everything.
A little bit related: #6579
dolsem commentedon Aug 5, 2020
I think it'd be great to implement this alongside #38671, so that generic regexes keep their current typing, but regex literals have strongly typed capturing groups.
And generalize them so that:
acutmore commentedon Jun 1, 2021
I really like the idea of extracting the named group static type information from RegExp literals. I'm curious how people imagine this 'metadata' would be associated with the RegExp literal before it's passed to
match? As the RegExp instance itself has no structure that reveals its groups. Is there already an existing pattern in TypeScript's core type definitions for this?EDIT: ah ignore me. I re-read the thread properly and realized we don't need to expose it.
webstrand commentedon Jun 17, 2021
The RegExp could be represented as a literal in the type system, i.e.
That'd be a lot less verbose than
Regex<{ FirstFour: string, NextFour: string | undefined }. And it'd be possible (though I don't know if it'd be efficient) to track dependencies between capture groups, for example:/(?<A>foo(?<B>bar))|(?<C>baz)/would have the effective typeRegex<{ A: string, B: string } | { A: undefined, B: undefined, C: string }>.Thankfully JavaScript doesn't have branch reset groups.
hlovdal commentedon Sep 17, 2021
For everyone that wants to have type safety and auto completion on the
groupspart right now you can declare the variable the match result is stored in as theRegExpMatchArrayWithGroupstype below like the following:The
RegExpMatchArrayWithGroupstype needs a type argument where all the group names in the regex are duplicated, so there is no automatic parsing from it, but when things are in the same statement this should be quite maintainable.Definitions:
Pyrolistical commentedon Aug 11, 2022
Thanks hlovdal. I took your idea made it easier to use.
Playground
connebs commentedon Oct 15, 2022
I personally prefer just using a Union type versus using an array of strings (saves having to type square brackets if you only have one group), so mine looks like this:
Usage:
const match: RegExpGroups<'file' | 'line' | 'error'> = ...wmertens commentedon Jun 7, 2023
Would it not be possible for TS to fully grok regexes instead of having to type them manually?
If there's a named group,
groupswill exist and have the name as a member, and if the match is optional it will be| undefined.Since regexes are an integral part of JS, kinda makes sense?
sdegutis commentedon Aug 9, 2024
VS Code already highlights the group names inside a regex, so surely it's not hard to tokenize them inside TS and attach the names as part of the regex's type?
sdegutis commentedon Aug 9, 2024
I'd be glad to put effort towards that feature if there's not already work being done towards it, as long as someone can help me figure out where to get started in the codebase. (I've dug into it before, but that was like 8 years ago.)
bgmort commentedon Aug 21, 2024
An iteration on the ideas from hlovdal and others above, to be able apply the type directly to the regex:
Playground
sdegutis commentedon Aug 21, 2024
I've cloned TypeScript and am starting to look into how I might imlpement this.
Any clues to where I should start looking would be appreciated to help speed it up.
In the meantime, here's the simple function I'm using in imlib:
codpro2005 commentedon Jul 22, 2025
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.
jonnytest1 commentedon Sep 1, 2025
"This wouldn't be a breaking change in existing TypeScript/JavaScript code"
🤔 doesnt anything that adds more accurate types / type checking potentially break existing typescript code ?