【expressjs】剖析expressjs如何通过字符串传路径解析出typescript的提示?

可能是全网第一个分析的人,如果能帮助你,请点个关注呗!😁

在这里插入图片描述

一、写在前面

一开始我也觉得这个功能简直泰裤辣!完全不需要自己重新定义一个类型就可以自动检测,后面发现实现起来并不难。这个功能主要使用类型推导出来的,分别为:去尾、获取参数key、分配到对象,这三个步骤。下面简单说一下:

二、具体三部曲

①去尾

// 去尾类型
type RemoveTail<S extends string, Tail extends string> = S extends `${infer P}${Tail}` ? P : S;

以上类型你可以理解为把重要的内容P和无用的尾部分离出来,并且去掉Tail无用部分。

以下为简单分析事例

// 去尾类型
type RemoveTail<S extends string, Tail extends string> = 
S extends `${infer P}${Tail}` ? P : S;

// 模拟一个字符串
const c = 'aaaa/abc/:id'

// 结果类型
type newD = RemoveTail<typeof c, `/${string}`>
// 此时newD为aaaa

②获取对应参数

// 获取对应参数
type GetRouteParameter<S extends string> = RemoveTail<
    RemoveTail<RemoveTail<S, `/${string}`>, `-${string}`>,
    `.${string}`
>;

以上类型你很清晰看到他会把/xxx-xxx.xxx此类部分全部删掉。那怎么叫做获取参数呢?因为他要配合extendsinfer使用
以下为具体示例



// 去尾类型
type RemoveTail<S extends string, Tail extends string> = 
S extends `${infer P}${Tail}` ? P : S;

// 获取对应参数
type GetRouteParameter<S extends string> = RemoveTail<
    RemoveTail<RemoveTail<S, `/${string}`>, `-${string}`>,
    `.${string}`
>;

// 模拟一个字符串
const c = 'aaaa/abc/:id'

// 真正获取对应参数
type RealParamter<T> = T extends `${string}:${infer Rest}`
? GetRouteParameter<Rest> 
: T;

type resType = RealParamter<typeof c>
// 此时计算出来的resType 为id

是不是很开心,这时候你已经完成了一半了😊😊😊
但是问题又来了,你会发现,你添加c添加多一个:user_id也会被忽略,加要看③步骤了

③分配到对象

// 修改第二步事例代码,我们可以通过递归的方式,把第一个参数后面的参数都输出
type RealParamter<T> = T extends `${string}:${infer Rest}`
? (GetRouteParameter<Rest> extends never
    ? {}
    : { [P in GetRouteParameter<Rest>]: string })
& (Rest extends `${GetRouteParameter<Rest>}${infer Next}`
    ? RealParamter<Next>
    : unknown)
: {};

type resType = RealParamter<typeof c>
// 此时输出 { id: string } & { user_id: string }

收工了老铁,官方源码位置

在这里插入图片描述

整个事例



// 去尾类型
type RemoveTail<S extends string, Tail extends string> = 
S extends `${infer P}${Tail}` ? P : S;

// 获取对应参数
type GetRouteParameter<S extends string> = RemoveTail<
    RemoveTail<RemoveTail<S, `/${string}`>, `-${string}`>,
    `.${string}`
>;

interface ParamsDictionary {
    [key: string]: string;
}
// 模拟一个字符串
const c = 'aaaa/abc/:id/:user_id'

// 真正获取对应参数
type RealParamter<T extends string> = T extends `${string}:${infer Rest}`
? (GetRouteParameter<Rest> extends never
    ? ParamsDictionary
    : { [P in GetRouteParameter<Rest>]: string })
& (Rest extends `${GetRouteParameter<Rest>}${infer Next}`
    ? RealParamter<Next>
    : unknown)
: {};

interface TestFunc {
    <
        Route extends string,
    >(path: Route) : RealParamter<typeof path>
}

const b: TestFunc = (path) => {
    const obj: ParamsDictionary = {}
    path.replace(/\/\:([^\/]+)/g, ($0, $1) => {
        if (typeof $1 === 'string') {
            obj[$1] = '';
        }
        return ''
    })
    return (obj as RealParamter<typeof path>)
}
console.log(b(c).id)

点赞关注转发,三连❤❤❤

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值