TypeScript 杂记七 《JSON Parser》

TypeScript 杂记七 《JSON Parser》

JSON Parser

思路

  • 先写主类型的大概
    • 如果是 {} 包裹则返回 ParserObject
    • 如果是 [] 包裹则返回 ParserArray
    • 否则返回原本的数据,这里我们额外处理一下 true,false,null
    • 不考虑 Numbers 和 Unicode
type Parser<T extends string> = T extends `{${infer S}}`
  ? ParserObject<S>
  : T extends `[${infer S}]`
  ? ParserArray<S>
  : T extends "true"
  ? true
  : T extends "false"
  ? false
  : T extends "null"
  ? null
  : // Numbers and Unicode escape (\uxxxx) in JSON can be ignored. You needn't to parse them.
    T;
  • 考虑到下边几种情况,因此我们要先处理一下数据
    • " {"a":1} " 处理前后空格
    • "aaa" 返回的是 "\"aaa\"",因此需要处理一下前后的引号
type TrimBase<
  T extends string,
  R extends string = " "
> = T extends `${R}${infer S}`
  ? TrimBase<S, R>
  : T extends `${infer S}${R}`
  ? TrimBase<S, R>
  : T;
// 处理空格->处理引号
type Trim<T extends string> = TrimBase<TrimBase<T>, '"'>;

type ParserHelper<T extends string> = T extends `{${infer S}}`
  ? ParserObject<Trim<S>> // 特殊解决一下 {    } 这种情况
  : T extends `[${infer S}]`
  ? ParserArray<S>
  : T extends "true"
  ? true
  : T extends "false"
  ? false
  : T extends "null"
  ? null
  : // Numbers and Unicode escape (\uxxxx) in JSON can be ignored. You needn't to parse them.
    T;
type Parser<T extends string> = ParserHelper<Trim<T>>;
  • 采用递归的形式

    • 先解析出最一层的数据,拿到 key 和 value
    • value 则再次调用 Parser
    • 重复第一步
  • ParserArray 的实现

    • 传入的数据不带去掉最外层的 []
    • 理论上对于一个普通数字,遇到 , 则前边的内容的表示是一项
    • 但是因为有可能是一个对象或者数组我们需要额外处理一下
      • V 用来临时存储数据
      • L 用来存储遇到的 [ { 个数
      • 如果遇到 [ 或者 { 则 L 数组加一
      • 如果遇到 ] 或者 } 则 L 数组减一
      • 如果遇到 , 且 L 数组为空,则表示一项完成了,把 V 存到 R 里边,继续下一项
      • 否则就把对应的字符加入到 V 中
    • 注意:存入的 V 值,需要递归去调用 Parser
type ParserArray<
  T extends string,
  R extends string[] = [],
  V extends string = "",
  L extends unknown[] = []
> = T extends `${infer S}${infer E}`
  ? S extends ","
    ? L extends []
      ? ParserArray<E, [...R, Parser<V>], "", L>
      : ParserArray<E, R, `${V}${S}`, L>
    : S extends "[" | "{"
    ? ParserArray<E, R, `${V}${S}`, [...L, unknown]>
    : S extends "}" | "]"
    ? L extends [unknown, ...infer B]
      ? ParserArray<E, R, `${V}${S}`, B>
      : ParserArray<E, R, `${V}${S}`, L>
    : ParserArray<E, R, `${V}${S}`, L>
  : [...R, Parser<V>];
  • ParserObject 的实现
    • 不同的是我们需要两个参数,用来存储 K 和 V
    • L=false 获取 K,只要遇到 : 就停止前边的内容就是对应的 key
    • L=true 获取值,这里的逻辑就和数组是一样的,不同的是这里只求一项
    • 求出 value 的时候,我们把 K 和 V 存到 R 中,重新开始下一项
type ParserObject<
  T extends string,
  R extends Record<string, any> = {},
  K extends string = "",
  V extends string = "",
  F extends boolean = false,
  L extends unknown[] = []
> = T extends `${infer S}${infer E}`
  ? F extends false
    ? S extends ":"
      ? ParserObject<E, R, Trim<K>, V, true, L>
      : ParserObject<E, R, `${K}${S}`, V, F, L>
    : S extends ","
    ? L extends []
      ? ParserObject<
          E,
          { [P in keyof R]: R[P] } & { [P in K]: Parser<V> },
          "",
          "",
          false,
          L
        >
      : ParserObject<E, R, K, `${V}${S}`, F, L>
    : S extends "[" | "{"
    ? ParserObject<E, R, K, `${V}${S}`, F, [...L, unknown]>
    : S extends "]" | "}"
    ? L extends [unknown, ...infer B]
      ? ParserObject<E, R, K, `${V}${S}`, F, B>
      : ParserObject<E, R, K, `${V}${S}`, F, L>
    : ParserObject<E, R, K, `${V}${S}`, F, L>
  : K extends ""
  ? { [P in keyof R]: R[P] }
  : ParserObject<
      "",
      { [P in keyof R]: R[P] } & { [P in K]: Parser<V> },
      "",
      "",
      false,
      L
    >;

完整示例

type TrimBase<
  T extends string,
  R extends string = " "
> = T extends `${R}${infer S}`
  ? TrimBase<S, R>
  : T extends `${infer S}${R}`
  ? TrimBase<S, R>
  : T;
type Trim<T extends string> = TrimBase<TrimBase<T>, '"'>;

type ParserObject<
  T extends string,
  R extends Record<string, any> = {},
  K extends string = "",
  V extends string = "",
  F extends boolean = false,
  L extends unknown[] = []
> = T extends `${infer S}${infer E}`
  ? F extends false
    ? S extends ":"
      ? ParserObject<E, R, Trim<K>, V, true, L>
      : ParserObject<E, R, `${K}${S}`, V, F, L>
    : S extends ","
    ? L extends []
      ? ParserObject<
          E,
          { [P in keyof R]: R[P] } & { [P in K]: Parser<V> },
          "",
          "",
          false,
          L
        >
      : ParserObject<E, R, K, `${V}${S}`, F, L>
    : S extends "[" | "{"
    ? ParserObject<E, R, K, `${V}${S}`, F, [...L, unknown]>
    : S extends "]" | "}"
    ? L extends [unknown, ...infer B]
      ? ParserObject<E, R, K, `${V}${S}`, F, B>
      : ParserObject<E, R, K, `${V}${S}`, F, L>
    : ParserObject<E, R, K, `${V}${S}`, F, L>
  : K extends ""
  ? { [P in keyof R]: R[P] }
  : ParserObject<
      "",
      { [P in keyof R]: R[P] } & { [P in K]: Parser<V> },
      "",
      "",
      false,
      L
    >;

type ParserArray<
  T extends string,
  R extends string[] = [],
  V extends string = "",
  L extends unknown[] = []
> = T extends `${infer S}${infer E}`
  ? S extends ","
    ? L extends []
      ? ParserArray<E, [...R, Parser<V>], "", L>
      : ParserArray<E, R, `${V}${S}`, L>
    : S extends "[" | "{"
    ? ParserArray<E, R, `${V}${S}`, [...L, unknown]>
    : S extends "}" | "]"
    ? L extends [unknown, ...infer B]
      ? ParserArray<E, R, `${V}${S}`, B>
      : ParserArray<E, R, `${V}${S}`, L>
    : ParserArray<E, R, `${V}${S}`, L>
  : [...R, Parser<V>];

type ParserHelper<T extends string> = T extends `{${infer S}}`
  ? ParserObject<Trim<S>>
  : T extends `[${infer S}]`
  ? ParserArray<S>
  : T extends "true"
  ? true
  : T extends "false"
  ? false
  : T extends "null"
  ? null
  : // Numbers and Unicode escape (\uxxxx) in JSON can be ignored. You needn't to parse them.
    T;

type Parser<T extends string> = ParserHelper<Trim<T>>;

测试

type A =
  Parser<'  { "asdasd ":{} , "   a123  "  :  true,"b123":{"b1acads": 1," b2":{"aasd ":false},"b3asda":2},"c":3,"d":{"d":null}}'>;
// type A = {
//   'asdasd ': {}
//   '   a123  ': true
//   b123: {
//     b1acads: '1'
//     ' b2': {
//       'aasd ': false
//     }
//     b3asda: '2'
//   }
//   c: '3'
//   d: {
//     d: null
//   }
// }

type B = Parser<'[  1  ,true, false,null ,{  },{ " a ":1,"b":{"b":"2"}},2,3]'>;
// type B = [
//   '1',
//   true,
//   false,
//   null,
//   {},
//   {
//     'a ': '1'
//     b: {
//       b: '2'
//     }
//   },
//   '2',
//   '3',
// ]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值