A minimal, statically typed alternative to JavaScript's RegExp.
const groups1 = new RegExp('^(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})$', 'g').exec('2000-10-24')!.groups; // ⤴ '{ [key: string]: string; } | undefined' 🤮 const groups2 = typedRegExp('^(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})$', 'g').exec('2000-10-24')!.groups; // ⤴ '{ year: string, month: string, day: string }' 🥰▶ Try it in the TypeScript Playground
- Install
ts-regexp
# Using npm npm install ts-regexp # Using yarn yarn add ts-regexp # Using pnpm pnpm add ts-regexp- Then import
typedRegExp:
import { typedRegExp } from 'ts-regexp';Import and use typedRegExp just like the native RegExp constructor:
import { typedRegExp } from 'ts-regexp'; const datePattern = typedRegExp('(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})'); const emailPattern = typedRegExp('^(?<local>[a-z0-9._%+-]+)@(?<domain>[a-z0-9.-]+\.[a-z]{2,})$', 'i');The function signature is:
typedRegExp(pattern: string, flags?: string)Note:
typedRegExpreturns a plain object, not aRegExpinstance.
All standard RegExp methods work exactly as expected, but with equivalent or improved typing:
const pattern = typedRegExp('(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})', 'gid'); // Standard methods pattern.exec('2000-10-24')!.groups; // { year: string; month: string; day: string; } pattern.test('2000-10-24'); // boolean // Access RegExp properties pattern.source; // "(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})" pattern.flags; // "dgi" pattern.global; // true pattern.sticky; // false // ...Each RegExp-related string.prototype method is available as ${MethodName}In with equivalent or improved typing:
const datePattern = typedRegExp('(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})'); const text = '1976-11-21'; // Instead of: text.match(pattern) const match = datePattern.matchIn(text); // typed match // Instead of: text.replace(pattern, replacement) const formatted1 = datePattern.replaceIn(text, '$<day>/$<month>/$<year>'); const formatted2 = datePattern.replaceIn(text, (match, year, month, day, offset, string, groups) => `${groups.day}/${groups.month}/${groups.year}`); // typed arguments // Other inversed methods datePattern.searchIn(text); // like text.search(pattern) datePattern.splitIn(text); // like text.split(pattern)When using the global (g) flag, additional methods become available:
const digitPattern = typedRegExp('\\d', 'g'); // Only available with 'g' flag digitPattern.matchAllIn('1973-12-08'); // like text.matchAll(pattern) digitPattern.replaceAllIn('123-456', '#'); // like text.replaceAll(pattern, replacement)If you need access to the underlying RegExp instance:
const pattern = typedRegExp('\\d+'); const nativeRegExp = pattern.regExp; // Regular RegExp instance- ✅ Strictly typed named & unnamed capture groups
- ✅ Supports contextual awareness
- ✅ Parses:
- nested groups
- different group types (non-capturing, lookarounds, named captures, etc.)
- alternation
- character classes and escaped characters
- ✅ Infers group optionality from quantifiers (
?,*,{n,m}) - ✅ Validates flags
- ✅ Supports dynamic (non-literal) pattern + flag inputs
📋 Planned