I've been wanting to implement a real regex engine in TypeScript types, but alas its a lot of work. So Instead I implemented a simple one from Nick Drane
// https://nickdrane.com/build-your-own-regex/
// https://github.com/nadrane/build-your-own-regex
type Empty = '' | null | undefined;
type Eq<L, R, T=true, F=false> = L extends R ? R extends L ? T : F : F;
type StartsWith<P extends string, T extends string> = T extends `${infer F}${infer Rest}` ? Eq<F,P,Rest> : never;
type First<T> = T extends `${infer F}${string}` ? F : never;
type Falsy = never | false | undefined | null;
type And<L,R> = L extends Falsy ? false : R extends Falsy ? false : true ;
type Extends<T,E> = T extends E ? true : false;
type S1 = StartsWith< '^', '^12'>;
type Slice2<T extends string> = Slice<T,2>extends [infer Left, infer Right extends string] ? Right : '';
type Slice1<T> = T extends `${infer F}${infer R}` ? R : never;
type StrToTuple<S extends string> = S extends '' ? [] : S extends `${infer F}${infer Rest}` ? [F, ...StrToTuple<Rest>] : never;
type _Slice<T extends readonly any[], N extends number, Ret extends readonly any[] = []> = Ret['length'] extends N ? [ Ret, T] : T extends [ infer F, ...infer Rest] ? _Slice<Rest, N, [...Ret, F]> : [Ret, T]
type TupleToStr<T extends readonly string[], Ret extends string = ''> = T extends [infer F extends string, ...infer Rest extends readonly string[]] ? Rest extends readonly string[] ? Rest['length'] extends 0 ? `${Ret}${F}` : TupleToStr<Rest, `${Ret}${F}`> : [] : [];
type Slice<T extends string, N extends number> = _Slice<StrToTuple<T>, N> extends [infer Left extends readonly string[], infer Right extends readonly string[]] ? [TupleToStr<Left>, TupleToStr<Right>] : never ;
type OpString = string | null | undefined;
type MatchOne<P, T> = P extends Empty ? true : T extends Empty ? false : P extends '.' ? true : Eq<P,T>;
type MatchQuestion<P extends string,T extends string> = And<MatchOne<First<P>, First<T>>, Match<Slice2<P>, Slice1<T>>> extends true ? true : Match<Slice2<P>,T>;
type MatchStar<P extends string,T extends string> = And<MatchOne<First<P>, First<T>>, Match<P, Slice1<T>>> extends true ? true : never;
type MatchGroup<P extends string, T extends string> =
P extends `${infer GroupPattern})${infer GroupEnd}` ?
GroupEnd extends `?${infer RemainderPattern }` ?
Slice<T, GroupPattern['length']> extends [infer Left extends string, infer Right extends string] ?
And<Match<GroupPattern, Left>, Match<RemainderPattern, Right>> extends true ? true : Match<RemainderPattern, T> : never :
GroupEnd extends `*${infer RemainderPattern}` ?
Slice<T, GroupPattern['length']> extends [infer Left extends string, infer Right extends string] ?
And<Match<GroupPattern, Left>, Match<P,Right>> extends true ? true : Match<RemainderPattern, T> :
never :
Slice<T, GroupPattern['length']> extends [infer Left extends string, infer Right extends string] ?
And<Match<GroupPattern, Left>, Match<GroupEnd, Right>> : never : never
;
type Match<P extends string, T extends string> =
P extends Empty ? true :
And<Extends<T, Empty>, Extends<P,'$'>> extends true ? true :
P extends `${infer F}?${string}` ? MatchQuestion<P, T> :
P extends `${infer F}*${string}` ? MatchStar<P, T> :
P extends `(${string}` ? MatchGroup<P,T> :
Slice<P, 1> extends [infer Pat0 extends string, infer Pat1 extends string] ?
Slice<T, 1> extends [infer Text0 extends string, infer Text1 extends string] ?
And<MatchOne<Pat0,Text0>, Match<Pat1, Text1>> : false : true;
type Search<P extends string, T extends string> = P extends `^${infer Rest}` ? Match<Rest, T> : Match<`.*${P}`, T>;
type Expect<Result,Expected,Message> = Result extends Expected ? true : {Result:Result, Expected:Expected, Message:Message};
type Assert<S,M> = Expect<S, true, M>;
type MatchOne1 = Assert<MatchOne<'a', 'a'>, 'single letter match'>;
type MatchOne1_1 = Assert<MatchOne<'.', 'a'>, 'single letter match'>;
type MatchOne2 = Assert<MatchOne<'', ''>, 'should return true when the pattern is empty or undefined'>;
type MatchOne3 = Expect<MatchOne<'a', 'c'>, false, 'should return false when the text is an empty string or undefined but the pattern is defined'>;
type Match1 = Assert<Match<'', 'abc'>,"should return true if given an empty pattern">;
type Match2 = Assert<Match<'$', ''>,"should return true if given an empty pattern">;
type Match3 = Expect<Match<'$', 'abc'>,false,"should match an empty string to the end of line pattern">;
type Match4 = Assert<Match<'ab', 'ab'>, "exact match">;
type Match5 = Assert<Match<'abc', 'abc'>, "exact match">;
type Match6 = Expect<Match<'abc', 'ab'>,false, "exact match">;
type Search1 = Expect<Search<"i am (the) hulk", "i am the hulk">, true, 'matches all characters placed within grouping operators'>
type Search2 = Assert<Search<"b*", "aaaaa">,'should match 0 or more characters following an *'>;
type Search3 = Assert<Search<"this* i*s the str*ing", "thissss s the strrring">, 'should match 0 or more characters following an *'>;