How to Define a Regex-Matched String Type in TypeScript ?
In TypeScript, you can define a type that represents a string matching a specific regular expression using different approaches.
Below are the approaches used to define a regex-matched string type in Typescript:
Table of Content
- Template Literal Types with Branding
- Type Assertion with Function
- Template Literal Types Only
- Using Regular Expression Objects
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. When we talk about a “regex-matched string” in the context of TypeScript or programming in general, it means a string that adheres to the specified regex pattern.
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.
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
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.
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.
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.
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 = "nikunj.sonigara@gfg.com" 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: nikunj.sonigara@gfg.com
Output:
nikunj.sonigara@gfg.com
Contact Us