TS,函数有两个参数,根据第一个参数约束第二个参数,并且推断出最终的结果。
比如我需要一个合并path和参数的函数,根据path来约束所传的参数,最终拼接path和params得出最终的string,比如:
type Path2Params = {
'/order/detail': { orderId: string };
'/product/list': { type: string; pageSize: string; pageNo: string };
};
const orderParams: Path2Params['/order/detail'] = { orderId: '123' };
const productListParams: Path2Params['/product/list'] = { type: 'electronics', pageSize: '10', pageNo: '1' };
通过函数能推断出orderUrl为/order/detail?orderId=123
,productListUrl为/product/list?type=electronics&pageSize=10&pageNo=1
这是我自己的实现,但是有一些问题:
type Path2Params = {
'/order/detail': { orderId: string };
'/product/list': { type: string; pageSize: string; pageNo: string };
};
type BuildQueryString<TParams extends Record<string, string>> = {
[K in keyof TParams]: `${Extract<K, string>}=${TParams[K]}`;
}[keyof TParams];
type FullUrl<
TPath extends string,
TParams extends Record<string, string>,
> = `${TPath}${TParams extends Record<string, never> ? '' : '?'}${BuildQueryString<TParams>}`;
/**
* 构建一个带有查询参数的URL字符串。
* @param path 路径参数,必须是`Path2Params`类型的键。
* @param params 查询参数,根据路径参数`path`在`Path2Params`中定义的类型。
* @returns 返回一个完整的URL字符串,包括路径和编码后的查询参数。
* @template TPath `Path2Params`中的键类型,用于确保类型安全。
* @template TParams `Path2Params`中由`TPath`指定的键对应的值的类型,用于确保类型安全。
*/
function buildStringWithParams<TPath extends keyof Path2Params, TParams extends Path2Params[TPath]>(
path: TPath,
params: TParams,
): FullUrl<TPath, TParams> {
// 优化:使用数组和join来减少字符串操作的开销
const encodedParams = Object.entries(params).map(([key, value]) => {
// 安全性优化:确保value经过适当的编码
const encodedValue = encodeURIComponent(value);
// 类型安全优化:不再需要as string,因为value已经被编码为字符串
return `${encodeURIComponent(key)}=${encodedValue}`;
});
const queryString = encodedParams.join('&');
return `${path}${queryString ? '?' : ''}${queryString}` as FullUrl<TPath, TParams>;
}
const orderParams: Path2Params['/order/detail'] = { orderId: '123' };
const productListParams: Path2Params['/product/list'] = { type: 'electronics', pageSize: '10', pageNo: '1' };
const orderUrl = buildStringWithParams('/order/detail', orderParams);
const productListUrl = buildStringWithParams('/product/list', productListParams);
orderUrl被推断成为/order/detail?orderId=${string}
,productListUrl被推断成为联合类型了,而我希望函数能直接正确推断出来结果,所以怎么改?
buildStringWithParams函数能够不在运行的情况下就能推断出正确的结果
orderUrl为/order/detail?orderId=123
productListUrl为/product/list?type=electronics&pageSize=10&pageNo=1