How to Define a Regex-Matched String Type in TypeScript ?
Last Updated :
11 Jul, 2024
Defining a regex-matched string type in TypeScript means creating a type that ensures a string adheres to a specific regular expression pattern. This enhances type safety by validating strings at compile or runtime, ensuring they match predefined formats.
What is a Regex-Matched String?
A "regex-matched string" refers to a string that satisfies a specific pattern or regular expression (regex). A regular expression is a sequence of characters that defines a search pattern. In the context of TypeScript or programming in general, a "regex-matched string" means a string that adheres to the specified regex pattern.
Below are the approaches used to define a regex-matched string type in Typescript:
Approach 1: Template Literal Types with Branding
This approach uses template literal types along with a branding technique to create a branded string type that matches a specific regex pattern.
Example: here, we want to create a type RegexMatchedString that represents a string adhering to a specific regex pattern for a phone number. The template literal type with branding ensures that any string assigned to this type matches the pattern.
JavaScript
type RegexMatchedString<Pattern extends string> =
`${string & { __brand: Pattern }}`;
let validPhoneNumber: RegexMatchedString<"\d{3}-\d{3}-\d{4}"> =
"123-456-7890" as RegexMatchedString<"\d{3}-\d{3}-\d{4}">;
// This will result in a type error because "invalid-number"
// does not match the pattern:
// let invalidPhoneNumber: RegexMatchedString<"\d{3}-\d{3}-\d{4}"> =
// "invalid-number" as RegexMatchedString<"\d{3}-\d{3}-\d{4}">;
console.log(validPhoneNumber);
Output:
"123-456-7890"
Approach 2: Type Assertion with Function
This approach involves using a type assertion function to ensure that a string matches a given regex pattern at runtime.
Example: here, we want to assert that a string adheres to a specific regex pattern for a hexadecimal color code. The type HexColor is created using a type assertion function, which checks the pattern at runtime.
JavaScript
type HexColor = string;
function assertHexColor(value: string): asserts value is HexColor {
const hexColorRegex = /^#([0-9a-fA-F]{3}){1,2}$/;
if (!hexColorRegex.test(value)) {
throw new Error(`"${value}" is not a valid hexadecimal color code.`);
}
}
// Example Usage:
let validColor: HexColor = "#1a2b3c";
// The type enforces that the string adheres to
// the specified hexadecimal color code pattern.
// This will result in a runtime error because
// "#invalid" is not a valid color code:
// assertHexColor("#invalid");
console.log(validColor); // Output: #1a2b3c
Output:
#1a2b3c
Approach 3: Template Literal Types Only
This approach relies solely on template literal types without additional runtime functions. It uses the ${string & { __brand: Pattern }} template literal type.
Example: here, we'll use a template literal type to represent a string adhering to a specific regex pattern for a date in the format "YYYY-MM-DD". The template literal type enforces the pattern at compile time.
JavaScript
type DateString = `${string & { __brand: "\\d{4}-\\d{2}-\\d{2}" }}`;
// Example Usage:
let validDate: DateString = "2022-01-15" as DateString;
// The type enforces that the string adheres
// to the specified date format pattern.
// This will result in a type error because
// "invalid-date" does not match the pattern:
// let invalidDate: DateString = "invalid-date" as DateString;
console.log(validDate); // Output: 2022-01-15
Output:
2022-01-15
Approach 4: Using Regular Expression Objects
In this approach, we directly use regular expression objects to define a type that represents a string matching a specific regular expression.
Syntax:
type RegexMatchedString<Pattern extends RegExp> = string & { __regexPattern: Pattern };Example: Below is the implementation of the above-discussed approach.
JavaScript
type RegexMatchedString<Pattern extends RegExp> = string & { __regexPattern: Pattern };
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
type Email = RegexMatchedString<typeof emailRegex>;
function assertMatchesPattern(value: string, pattern: RegExp):
asserts value is RegexMatchedString<typeof pattern> {
if (!pattern.test(value)) {
throw new Error(`"${value}" does not match the specified pattern.`);
}
}
const validEmail: Email = "[email protected]" as Email;
// The type enforces that the string adheres to
// the specified email pattern.
// This will result in a runtime error because
// "invalid-email" does not match the pattern:
// assertMatchesPattern("invalid-email", emailRegex);
console.log(validEmail);
Output:
[email protected]
Explore
TypeScript Tutorial
8 min read
TypeScript Basics
TypeScript primitive types
TypeScript Object types
TypeScript other types
TypeScript combining types
TypeScript Assertions
TypeScript Functions
TypeScript interfaces and aliases
TypeScript classes