目前只能解析类似/user/:id/update/:id2
且始终为字符串的内容。
type Data = "/user/:id/update/:id2" // -> { id: string, id2: string }
type Parse<T extends string, Memo extends string[] = []> =
T extends `${infer Part}/${infer Others}`
? Part extends `:${infer Value}` ? Parse<Others, [...Memo, Value]> : Parse<Others, Memo>
: T extends `:${infer Value}` ? [...Memo, Value] : Memo;
type TupleToObject<T extends string[]> = {
[Key in T[number]]: string
}
// { id: string, id2: string }
type Result = TupleToObject<Parse<Data>>
是否可以像这样解析某个时间"/user/:id(string)/update/:id2(number)/:id3"
?如果未指定,则默认为字符串。这会是:
{
id: string;
id2: number;
id3: string;
}
另外,是否可以让代码变得更简单。
首先,您需要从类型名称(例如url 中的
"string"
和 )到其相应类型的某种映射:"number"
然后我们可以编写
KV<T>
,它接受一个字符串 like"foo(bar)"
并将其转换为类似 的类型{foo: TypeMap["bar"]}
,并接受一个字符串 like"foo"
(不带括号的类型名称)并将其转换为类似 的类型{foo: string}
:这应该是不言自明的;我们检查输入是否
T
是一个字符串,U
后跟一个V
括号中的字符串。V
如果是这样,我们会查找TypeName
(如果没有找到,我们默认为any
。您可能想做其他事情,但问题中没有指定,因此超出了此处的范围)。Record<U, TypeMap[V]>
使用实用程序类型的类型Record
是这样的。否则我们生产Record<T, string>
.现在我们可以
Parse
像您的方式那样编写尾递归条件类型,您可以在其中提取冒号 (:
) 之后直到下一个斜杠 (/
) 之前的所有文本。这成为 的输入,并且我们通过交集KV
累积输出(似乎没有理由跟踪标识符的顺序,因此我们不需要元组类型):A
当我们敲到最后一个冒号时,那里会出现一点皱纹,因为最后可能没有斜杠。所以我们必须记住也许还要再相交一个片段,这就是
T extends
${string}:${infer F} 的? KV<F> : unknown
来源。让我们测试一下:
看起来不错,输出符合预期。当然,这种递归类型有时可能会出现奇怪的边缘情况行为,因此根据预期用例进行彻底测试并准备重构总是一个好主意。
Playground 代码链接