Skip to content

Latest commit

 

History

History
175 lines (157 loc) · 5.09 KB

JSONSchema2TS.md

File metadata and controls

175 lines (157 loc) · 5.09 KB
标题 标签
JSONSchema2TS(json 数据转 ts 类型) extends,infer(继承,推断)

json 数据转 ts 类型。

  • 创建一个原始接口映射类型 P,包含字符串,数值和布尔类型。代码如下:
type P = {
  string: string;
  number: number;
  boolean: boolean;
};
  • 创建一个 H 类型,用于处理原始类型的情况,并且提供 2 个参数,第一个参数为 json 原始数据,第二个参数为索引值,默认取原始接口映射类型 P 的 key。判断是否存在 enum 属性,存在则返回读取 enum 属性的类型,否则返回对应的原始类型。代码如下:
type H<T, K extends keyof P> = T extends { enum: unknown[] }
  ? T['enum'][number]
  : P[K];
  • 创建一个 O 类型,用于处理对象接口的情况,首先判断参数 T 存在 properties 属性,并使用 infer 断言该属性的值应该是一个对象。接着判断存在 required 属性,并使用 infer 断言该属性的值应该是一个字符串数组,从断言的字符串数组中取出字符串属性,递归的设置属性值为必选,然后使用 Exclude 排除不在断言字符串数组中的属性,递归的设置属性值为可选,并且将两者合并起来,然后使用 Omit 类型排除掉 never 作为属性的值。如果不满足存在 required 属性,则将全部属性递归的设置为可选,如果不存在 properties 属性,则返回对象类型即Record<string,unknown>。代码如下:

ps: 注意这里递归不是递归 O,而是使用 JSONSchema2TS 类型递归。

type O<T> = T extends { properties: infer Prop extends Record<string, unknown> }
  ? T extends { required: infer R extends unknown[] }
    ? Omit<
        {
          [K in R[number] & keyof Prop]: JSONSchema2TS<Prop[K]>;
        } & {
          [K in Exclude<keyof Prop, R[number]>]?: JSONSchema2TS<Prop[K]>;
        },
        never
      >
    : {
        [K in keyof Prop]?: JSONSchema2TS<Prop[K]>;
      }
  : Record<string, unknown>;
  • 创建一个 A 类型,用于处理数组的情况,使用 infer 断言存在 items 属性,则递归,否则返回unknown []。代码如下:
type A<T> = T extends { items: infer I } ? JSONSchema2TS<I>[] : unknown[];
  • 类型 JSONSchema2TS 第一个参数为 T,使用 infer 断言存在 Type 属性,并判断 Type 是基础类型 P 的属性,则当做原始类型 H 来处理,如果 Type 是一个对象,则当做对象类型来处理,否则当做数组处理,否则返回 never。

代码如下:

type JSONSchema2TS<T> = T extends { Type: infer Type }
  ? Type extends keyof P
    ? H<T, Type>
    : Type extends 'object'
    ? O<T>
    : A<T>
  : never;

使用方式:

// + Primitive types
type JSONSchema2TSRes1 = JSONSchema2TS<{ type: 'string' }>; // string
type JSONSchema2TSRes2 = JSONSchema2TS<{ type: 'number' }>; // number
type JSONSchema2TSRes3 = JSONSchema2TS<{ type: 'boolean' }>; // boolean
// - Primitive types
// + Enums
type JSONSchema2TSRes4 = JSONSchema2TS<{
  type: 'string';
  enum: ['a', 'b', 'c'];
}>; // 'a' | 'b' | 'c'
type JSONSchema2TSRes5 = JSONSchema2TS<{ type: 'number'; enum: [1, 2, 3] }>; // 1 | 2 | 3
// - Enums
// + Object types
type JSONSchema2TSRes6 = JSONSchema2TS<{ type: 'object' }>; // Record<string, unknown>
type JSONSchema2TSRes7 = JSONSchema2TS<{ type: 'object'; properties: {} }>; // {}
type JSONSchema2TSRes8 = JSONSchema2TS<{
  type: 'object';
  properties: { a: { type: 'string' } };
}>;
// {
//    a?: string
// }
// - Object types
// + Arrays
type JSONSchema2TSRes9 = JSONSchema2TS<{ type: 'array' }>; // unknown[]
type JSONSchema2TSRes10 = JSONSchema2TS<{
  type: 'array';
  items: {
    type: 'string';
  };
}>; // string[]
type JSONSchema2TSRes11 = JSONSchema2TS<{
  type: 'array';
  items: {
    type: 'object';
  };
}>; // Record<string, unknown>[]
// - Arrays
// + Mixed types
type JSONSchema2TSRes12 = JSONSchema2TS<{
  type: 'object';
  properties: {
    a: {
      type: 'string';
      enum: ['a', 'b', 'c'];
    };
    b: {
      type: 'number';
    };
  };
}>;
// {
//     a?: 'a' | 'b' | 'c'
//     b?: number
// }
type JSONSchema2TSRes13 = JSONSchema2TS<{
  type: 'array';
  items: {
    type: 'object';
    properties: {
      a: {
        type: 'string';
      };
    };
  };
}>;
// {
//   a?: string
// }[]
// - Mixed types
// + Required fields
type JSONSchema2TSRes14 = JSONSchema2TS<{
  type: 'object';
  properties: {
    req1: { type: 'string' };
    req2: {
      type: 'object';
      properties: {
        a: {
          type: 'number';
        };
      };
      required: ['a'];
    };
    add1: { type: 'string' };
    add2: {
      type: 'array';
      items: {
        type: 'number';
      };
    };
  };
  required: ['req1', 'req2'];
}>;
// {
//     req1: string
//     req2: { a: number }
//     add1?: string
//     add2?: number[]
// }

应用场景

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