当前位置: 首页 > 工具软件 > RFCs > 使用案例 >

模拟 vue3.0 rfcs `createComponent` api 中的`props`类型推导

扈昀
2023-12-01

rfc 中类型推导部分 Type Inference

预期想实现的效果

createComponent({
  props: {
    foo: {
      type: String,
      required: true
    },
    bar: {
      type: Number
    },
    boo: Boolean,
    options: (null as any) as { msg: string },
    requiredOptions: {
      type: (null as any) as { msg: string },
      required: true
    }
  } as const,
  setup(props) {
    props.foo; // string
    props.bar; // number | undefined
    props.boo; // boolean | undefined
    props.options; // {msg: string } | undefined
    props.requiredOptions; // {msg: string }
  }
});
复制代码

String -> stringNumber -> numberBoolean -> boolean

在 ts 中

  • String对应的类型是StringConstructor
  • Number对应的类型是NumberConstructor
  • Boolean对应的类型是BooleanConstructor

但是,我们想要实现的是转换成小写的string | number | boolean

所以我们写个泛型来转换

type NormalizeType<T> = T extends StringConstructor
  ? string
  : T extends NumberConstructor
  ? number
  : T extends BooleanConstructor
  ? boolean
  : T;
复制代码

playground 预览链接

定义 prop 的类型

type BuiltInType<T> =
  | StringConstructor
  | NumberConstructor
  | BooleanConstructor
  | T;
复制代码

留个泛型是给复杂类型做兼容 rfc 复杂的 prop 类型

定义createComponent函数接收的props类型

type DefaultType<T> = {
  [key: string]:
    | {
        type?: BuiltInType<T>;
        require?: boolean;
      }
    | BuiltInType<T>;
};
复制代码

最关键的一步根据输入的props类型计算出来setup函数接收的形参props类型

type ReflexType<T> = {
  [key in keyof T]: T[key] extends { type: infer TYPE; required: true }
    ? NormalizeType<TYPE>
    : T[key] extends { type: infer TYPE }
    ? NormalizeType<TYPE> | undefined
    : NormalizeType<T[key]> | undefined
};
复制代码

组合出来createComponent函数定义

function createComponent<T extends DefaultType<any>>(props: {
  props: T;
  setup(props: ReflexType<T>): any;
}) {}
复制代码

完整代码

type BuiltInType<T> =
  | StringConstructor
  | NumberConstructor
  | BooleanConstructor
  | T;

type NormalizeType<T> = T extends StringConstructor
  ? string
  : T extends NumberConstructor
  ? number
  : T extends BooleanConstructor
  ? boolean
  : T;

type ReflexType<T> = {
  [key in keyof T]: T[key] extends { type: infer TYPE; required: true }
    ? NormalizeType<TYPE>
    : T[key] extends { type: infer TYPE }
    ? NormalizeType<TYPE> | undefined
    : NormalizeType<T[key]> | undefined
};

type DefaultType<T> = {
  [key: string]: { type?: BuiltInType<T>; require?: boolean } | BuiltInType<T>;
};

function createComponent<T extends DefaultType<any>>(props: {
  props: T;
  setup(props: ReflexType<T>): any;
}) {}

createComponent({
  props: {
    foo: {
      type: String,
      required: true
    },
    bar: {
      type: Number
    },
    boo: Boolean,
    options: (null as any) as { msg: string },
    requiredOptions: {
      type: (null as any) as { msg: string },
      required: true
    }
  } as const,
  setup(props) {
    props.foo;
    props.bar;
    props.boo;
    props.options;
    props.requiredOptions;
  }
});
复制代码

playground 预览链接

效果图

转载于:https://juejin.im/post/5d00a983e51d4556dc293613

 类似资料: