Regular Expressions in TypeScript: From Theory to Practice
Regular expressions (regex) are a powerful tool for working with strings. In TypeScript, they not only allow you to perform search, replace, and validation but also provide strict typing, which reduces the number of errors at the compilation stage. In this article, we will break down how to use regular expressions in TypeScript with real examples: from email validation to safe data extraction.
1. Creating and Typing Regular Expressions
In TypeScript, a regular expression can be created in two ways: using a literal or the RegExp constructor. The first method is preferable as it is shorter and does not require escaping backslashes.
// Literal (recommended way)const emailRegex: RegExp = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$/;
// Constructor (useful for dynamic patterns)const pattern: string = 'hello';const dynamicRegex: RegExp = new RegExp(pattern, 'gi');
console.log(emailRegex.test('user@example.com')); // trueconsole.log(dynamicRegex.test('Hello, world!')); // true (flag i ignores case)Note the type annotation : RegExp. TypeScript automatically infers the type for literals, but explicit specification helps document the code.
2. Flags and Their Typing
Flags modify the behavior of a regular expression. In TypeScript, the type of flags can be specified via a string literal or an enumeration. Let's look at the main flags:
- g — global search (does not stop after the first match);
- i — case-insensitive mode;
- m — multiline mode (^ and $ work for each line);
- s — dot matches newline character;
- u — Unicode support;
- y — search from the last found position (sticky).
// Typing flags via a stringconst regexWithFlags: RegExp = /test/gim;
// Checking flagsconsole.log(regexWithFlags.flags); // "gim"console.log(regexWithFlags.global); // trueconsole.log(regexWithFlags.ignoreCase); // trueconsole.log(regexWithFlags.multiline); // trueFor dynamic flags, use the string type, but it is better to restrict it to valid values using a literal union:
type RegexFlags = 'g' | 'i' | 'm' | 's' | 'u' | 'y';const flags: RegexFlags = 'gi'; // Error: 'gi' is not a single flag// Correct: pass a stringconst dynamicFlags: string = 'gi';const regex: RegExp = new RegExp('pattern', dynamicFlags);3. RegExp Methods and Typing Results
The main methods for working with regular expressions in TypeScript:
test()— returnsboolean;exec()— returnsRegExpExecArray | null;match()— a string method, returnsRegExpMatchArray | null;replace()— replaces matches and returns a string;search()— returns the index of the first match or -1.
Let's look at an example with exec(), which provides access to capture groups:
const dateRegex: RegExp = /(\\d{4})-(\\d{2})-(\\d{2})/;const dateStr: string = 'Today is 2025-03-15';
const match: RegExpExecArray | null = dateRegex.exec(dateStr);
if (match) { const [fullMatch, year, month, day] = match; console.log(`Year: ${year}, Month: ${month}, Day: ${day}`); // Output: Year: 2025, Month: 03, Day: 15} else { console.log('Date not found');}Note: match[0] is the full match, and indices 1, 2, 3 are the capture groups. TypeScript correctly infers types if you use destructuring.