Type-Level RegExp (WIP)
TypeScript type-level RegExp parser and matcher implemented using template literals.

Try on TypeScript Playground
or see examples in Playground and test folders.
Work In Progress, PRs and issues are welcome
Quick Setup
- Add
type-level-regexpdependency to your project
# Using pnpm
pnpm i -D type-level-regexp
# Using npm
npm i -D type-level-regexp
- Import
createRegExpfunction, pass in a RegExp string pattern to it creates aTypedRegExp, passing thisTypedRegExptoString.match(),String.matchAll()orString.replace()functions to get fully typed match result.
Basic Usage
match result will be fully typed if match against a literal stirng, or shows emumerated results if match against a dynamic string.
import { createRegExp, spreadRegExpIterator } from 'type-level-regexp'
/** string.match() */
const regExp = createRegExp('foO(?<g1>b[a-g]r)(?:BAz|(?<g2>qux))', ['i'])
const matchResult = 'prefix foobarbaz suffix'.match(regExp) // matching literal string
matchResult[0] // 'foobarbaz'
matchResult[1] // 'bar'
matchResult[3] // show type error `type '3' can't be used to index type 'RegExpMatchResult<...>`
matchResult.length // 3
matchResult.index // 7
matchResult.groups // { g1: "bar"; g2: undefined; }
/** string.replace() */
const regExp2 = createRegExp('(\\d{4})[-.](?<month>\\w{3,4})[-.](\\d{1,2})')
const replaceResult = '1991-Sept-15'.replace(regExp2, '__CODE_BLOCK_1__lt;month> $3, $1')
replaceResult // 'Sept 15, 1991'
/** string.matchAll() */
const regExp3 = createRegExp('c[a-z]{2}', ['g'])
const matchALlIterator = 'cat car caw cay caw cay'.matchAll(regExp3)
const spreadedResult = spreadRegExpIterator(matchALlIterator)
spreadedResult[2][0] // 'caw'
spreadedResult[3].index // 12
const InvalidRegExp = createRegExp('foo(bar')
// TypeScript error: Argument of type 'string' is not assignable to parameter of type 'RegExpSyntaxError<"Invalid regular expression, missing closing \`)\`">'
For TypeScript library authors, you can also import individual generic types to parse and match RegExp string at type-level and combine with your library's type-level features.
import { ParseRegExp, MatchRegExp } from 'type-level-regexp'
type MatchResult = MatchRegExp<'fooBAR42', ParseRegExp<'Fo[a-z](Bar)\\d{2}'>, 'i'>
type Matched = MatchResult[0] // 'fooBAR42'
type First = MatchResult[1] // 'BAR'
type RegExpAST = ParseRegExp<'foo(?<g1>bar)'>
// [{
// type: "string";
// value: "foo";
// }, {
// type: "namedCapture";
// name: "g1";
// value: [{
// type: "string";
// value: "bar";
// }];
// }]
Origin & Notice
The main purpose of this project is to test and demonstrate the possibility and limitations of writing a RegExp parser/matcher in TypeScript's type-level. Note that this may not be practically useful, but rather an interesting showcase.
The idea for this project originated while I was working on improving the type hints of string.match and replace in magic-regexp (created by the most inspiring, resourceful, and kind Daniel Roe from Nuxt, definitely check it out if you are working with RegExp and TypeScript!).
As the complexity grows, I start working on this separated repo to increase development speed and try out different iterations. It will be incorporate and use in magic-regexp, and Gabriel Vergnaud's awesome hotscript very soon.
Testing, feedbacks and PRs are welcome!
Features
- Export
createRegExpfunction to create aTypedRegExpthat replace your original/regex_pattern/regex object, which can be pass toString.match(),String.matchAll()andString.replace()functions and gets fully typed result. - Shows
RegExpSyntaxErrorif the provided RegExp pattern is invalid. - Enhance types of RegExp related
Stringfunctions (.match,matchAll,.replace...) for literal or dynamic typed string. - Result of
Stringfunctions matched exactly as runtime result. - Support all common RegExp tokens (incl. Lookarounds, Backreferences...etc), quantifiers (incl. greedy/lazy) and (
g,i) flags. - Export helper functions
spreadRegExpMatchArrayandspreadRegExpIteratorto get tuple type of match results and iterators. - Provide generic type
ParseRegExpto parse and RegExp string to AST. - Provide generic type
MatchRegExpto match giving string with a parsed RegExp. - Provide generic type
ResolvePermutationto permutation all possible matching string of given RegExp if possible (due to TypeScript type-level limitation) - More details please try on TypeScript Playground, or see tests files in Tests and Stackblitz. (examples in index.test-d.ts)
Example - type-safe args in replacing function of string.replace()
Example - spreaded string.matchAll() with union of RegExp pattern remain as tuple

RegExp Tokens & Flags
| Tokens | Description | Support |
|---|---|---|
. |
Matches any single character. | |
*, *? |
Matches zero or more occurrences (Greedy/Lazy). | |
+, *? |
Matches one or more occurrences (Greedy/Lazy). | |
?, ?? |
Matches zero or one occurrence (Greedy/Lazy). | |
^ |
Matches the start of a line. | |
$ |
Matches the end of a line. | |
\s, \S |
Matches any whitespace, non-whitespace character. | |
\d, \D |
Matches any digit, non-digit character. | |
\w, \W |
Matches any word, non-word character. | |
\b, \B |
Matches a word-boundary, non-word-boundary. | |
[abc] |
Matches any character in the set. | |
[^abc] |
Matches any character not in the set. | |
() |
Creates a capturing group. | |
(?:) |
Creates a non-capturing group. | |
(?<name>) |
Creates a named-capturing group. | |
| |
Matches either the expression before or after the vertical bar. | |
{n} |
Matches exactly n occurrences. |
|
{n,} |
Matches at least n occurrences. |
|
{n,m} |
Matches between n and m occurrences. |
|
(?=), (?!) |
Positive/Negative lookahead. | |
(?<=), (?<!) |
Positive/Negative lookbehind. |
| Flags | Description | Support |
|---|---|---|
g |
Global matching (matches all occurrences). | |
i |
Case-insensitive matching. |
Development
- Clone this repository
- Enable Corepack using
corepack enable(usenpm i -g corepackfor Node.js < 16.10) - Install dependencies using
pnpm install - Run interactive tests using
pnpm dev
License
Made with and
Published under MIT License.