Skip to content

Latest commit

 

History

History
84 lines (69 loc) · 4.78 KB

ParseQueryString.md

File metadata and controls

84 lines (69 loc) · 4.78 KB
标题 标签
ParseQueryString(解析 url 参数字符串) extends,infer(继承,推断)

解析 url 参数字符串。

  • 创建一个 SplitParams 类型,该类型传入一个字符串参数,返回将字符串依据&符号分割出来的字符串数组。使用 infer 从第一个字符开始推断,如果字符后跟&符号,并且包含剩余字符,则递归剩余字符,并把字符添加到数组中,否则返回由原始字符串组成的数组,代码如下所示:
type SplitParams<S extends string> = S extends `${infer E}&${infer R}`
  ? [E, ...SplitParams<R>]
  : [S];
  • 实现一个 SetProperty 类型,该类型接收三个参数,第一个参数为对象类型,第二个参数为属性名,继承 PropertyKey 类型,第三个参数为属性值,默认是 true。该类型返回一个对象,属性名则是 keyof T(第一个对象参数)与第二个参数的联合类型,属性值稍微复杂一点,首先判断属性名等于第二个参数并且是第一个参数对象的属性,并且根据该属性从第一个参数对象中找到的属性值等于第三个参数,则返回该属性值。如果属性值是任意数组,并且第三个参数也在该数组中,则返回该属性值,否则返回一个数组,将第三个参数和取得的对象中的属性值合并到一起,注意属性值需要展开,因为是一个数组,否则返回不展开的数组,否则返回第三个参数,否则如果属性名属于对象的属性名,则返回对应的属性值,否则返回 never。代码如下所示:
type SetProperty<T, K extends PropertyKey, V extends any = true> = {
  [P in keyof T | K]: P extends K
    ? P extends keyof T
      ? T[P] extends V
        ? T[P]
        : T[P] extends any[]
        ? V extends T[P][number]
          ? T[P]
          : [...T[P], V]
        : [T[P], V]
      : V
    : P extends keyof T
    ? T[P]
    : never;
};
  • 实现一个 MergeParams 类型,该类型支持传入一个字符串数组和一个对象类型,默认是空对象,主要用于将分割后的字符串数组转换成对应的对象。使用 infer 推断第一个参数数组的每一个元素,并从第一个元素开始推断,如果元素属于由属性名=属性值构成的字符串,则递归的合并剩余元素,第二个参数将变成 SetProperty 类型,需要注意会传入三个参数,即第二个参数,使用 infer 推断出来的属性名和属性值。如果元素只推断出一个属性名,则递归合并剩余元素同样是 SetProperty 类型,只是不传第三个参数,否则返回 never,否则返回第二个参数。代码如下所示:
type MergeParams<T extends string[], M = {}> = T extends [
  infer E,
  ...infer R extends string[]
]
  ? E extends `${infer K}=${infer V}`
    ? MergeParams<R, SetProperty<M, K, V>>
    : E extends `${infer K}`
    ? MergeParams<R, SetProperty<M, K>>
    : never
  : M;
  • 判断字符串是否是空字符串,如果是则返回空对象,否则使用 MergeParams 类型合并使用 SplitParams 类型分割而成的字符串数组。

代码如下:

type ParseQueryString<S extends string> = S extends ''
  ? {}
  : MergeParams<SplitParams<S>>;

使用方式:

type ParseQueryStringRes1 = ParseQueryString<''>; //  {}
type ParseQueryStringRes2 = ParseQueryString<'k1'>; //  { k1: true }
type ParseQueryStringRes3 = ParseQueryString<'k1&k1'>; //  { k1: true }
type ParseQueryStringRes4 = ParseQueryString<'k1&k2'>; //  { k1: true; k2: true }
type ParseQueryStringRes5 = ParseQueryString<'k1=v1'>; //  { k1: 'v1' }
type ParseQueryStringRes6 = ParseQueryString<'k1=v1&k1=v2'>; //  { k1: ['v1', 'v2'] }
type ParseQueryStringRes7 = ParseQueryString<'k1=v1&k2=v2'>; //  { k1: 'v1'; k2: 'v2' }
type ParseQueryStringRes8 = ParseQueryString<'k1=v1&k2=v2&k1=v2'>; //  { k1: ['v1', 'v2']; k2: 'v2' }
type ParseQueryStringRes9 = ParseQueryString<'k1=v1&k2'>; //  { k1: 'v1'; k2: true }
type ParseQueryStringRes10 = ParseQueryString<'k1=v1&k1=v1'>; //  { k1: 'v1' }
type ParseQueryStringRes11 = ParseQueryString<'k1=v1&k1=v2&k1=v1'>; //  { k1: ['v1', 'v2'] }
type ParseQueryStringRes12 = ParseQueryString<'k1=v1&k2=v1&k1=v2&k1=v1'>; //  { k1: ['v1', 'v2']; k2: 'v1' }
type ParseQueryStringRes13 = ParseQueryString<'k1=v1&k2=v2&k1=v2&k1=v3'>; //  { k1: ['v1', 'v2', 'v3']; k2: 'v2' }
type ParseQueryStringRes14 = ParseQueryString<'k1=v1&k1'>; //  { k1: ['v1', true] }
type ParseQueryStringRes15 = ParseQueryString<'k1&k1=v1'>; //  { k1: [true, 'v1'] }

应用场景

如下所示,鼠标悬浮到对应的类型变量可以查看类型。