Suppose I have types like this:
type SegmentBase = string;
type ParamSegment = `:${string}`;
type Segment = SegmentBase | ParamSegment;
type Path = `${Segment}/${Segment}`;
Is it now possible to construct a type Extractor<T extends Path> that extracts the ${string} part of a ParamSegment in the following way:
Extractor<'foo/:bar'>
// turns into
{
bar: string;
}
Extractor<':foo/:bar'>
// turns into
{
foo: string;
bar: string;
}
Extractor<'foo/bar'>
// turns into
{}
You need to create a recursive auxiliary type for this.
First, create a type that matches the parameter names
type _UnwrapParam<P extends string, S extends string[]> = P extends `:${infer Q}` ? [Q, ...S] : S;
type _Match<T extends string, S extends string[]> = T extends `${infer P}/${infer R}`
? [...UnwrapParam<P, S>, ..._Match<R, S>]
: _UnwrapParam<T, S>
export type Match<T extends string> = _Match<T, []>[number];
Then you can do
export type Extractor<T extends string> = {
[K in Match<T>]: string;
};
Edit: Since Typescript 4.5, it's better to implement the _Match type as bellow, so it can benefit from Tail recursion elimination.
type _Match<
T extends string,
S extends string[]
> = T extends `${infer P}/${infer R}`
? _Match<R, _UnwrapParam<P, S>>
: _UnwrapParam<T, S>;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With