根据字符串生成对象的函数返回类型最佳实践
替代
any的类型方案推荐 你这个解析URL参数的函数,用any确实太宽泛,即使对象结构未知,也有几种更合适的类型方案,按实用性从高到低给你列出来:
1. 最实用的基础方案:Record<string, string>
直接把返回类型改成Record<string, string>,它表示一个键为字符串、值为字符串的对象,比any安全得多,至少能约束键值的类型,避免后续误用:
const decodeParameters = (params: string): Record<string, string> => { return decodeURI(params) .split('&') .reduce((result, current) => { const [key, value] = current.split('='); if (key) { // 加个判断避免空键的情况 result[key] = value || ''; } return result; }, {} as Record<string, string>); // 断言初始值的类型 } const queryParametersObj1 = decodeParameters('file=index.ts'); // queryParametersObj1的类型是Record<string, string>,能提示属性均为字符串类型
这个方案不需要额外泛型,不管参数字符串是静态还是动态的,都能提供基础的类型安全,适合大多数场景。
2. 手动指定具体类型:泛型约束
如果调用函数时你清楚参数的结构,可以用泛型让函数返回你指定的类型,获得更精确的类型提示:
const decodeParameters = <T extends Record<string, string>>(params: string): T => { return decodeURI(params) .split('&') .reduce((result, current) => { const [key, value] = current.split('='); if (key) { result[key] = value || ''; } return result; }, {} as T); } // 调用时指定具体类型 const queryParametersObj1 = decodeParameters<{ file: string }>('file=index.ts'); // 现在queryParametersObj1的类型是{ file: string },能精确提示file属性
注意:这里的泛型是类型断言性质的,TypeScript不会验证参数字符串是否真的符合你指定的类型,需要你自己保证传入参数和指定类型匹配。
3. 进阶:自动推导字面量参数的类型(仅限静态字符串)
如果你的参数字符串是静态字面量(不是动态生成的),可以用模板字面量类型和工具类型让TypeScript自动推导返回对象的类型:
先定义工具类型拆分参数字符串:
type SplitParams<S extends string> = S extends `${infer K}=${infer V}&${infer Rest}` ? { [Key in K]: V } & SplitParams<Rest> : S extends `${infer K}=${infer V}` ? { [Key in K]: V } : {}; const decodeParameters = <S extends string>(params: S): SplitParams<DecodeURI<S>> => { return decodeURI(params) .split('&') .reduce((result, current) => { const [key, value] = current.split('='); if (key) { result[key as keyof SplitParams<DecodeURI<S>>] = value || ''; } return result; }, {} as SplitParams<DecodeURI<S>>); } // 自动推导类型 const queryParametersObj1 = decodeParameters('file=index.ts&type=ts'); // queryParametersObj1的类型自动推导为{ file: "index.ts"; type: "ts" }
这个方案的局限性是:只有传入的参数是字面量字符串时才会生效,如果是动态生成的字符串(比如变量),TypeScript无法推导具体类型,会退回到类似Record<string, string>的结构。
内容的提问来源于stack exchange,提问作者Tabares
相关产品推荐
相关产品推荐

