You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1 line
7.9 KiB

11 months ago
{"version":3,"file":"props.mjs","sources":["../../../../packages/utils/props.ts"],"sourcesContent":["import { warn } from 'vue'\nimport { isObject } from '@vue/shared'\nimport fromPairs from 'lodash/fromPairs'\nimport type { ExtractPropTypes, PropType } from '@vue/runtime-core'\nimport type { Mutable } from './types'\n\nconst wrapperKey = Symbol()\nexport type PropWrapper<T> = { [wrapperKey]: T }\n\nexport const propKey = '__elPropsReservedKey'\n\ntype ResolveProp<T> = ExtractPropTypes<{\n key: { type: T; required: true }\n}>['key']\ntype ResolvePropType<T> = ResolveProp<T> extends { type: infer V }\n ? V\n : ResolveProp<T>\ntype ResolvePropTypeWithReadonly<T> = Readonly<T> extends Readonly<\n Array<infer A>\n>\n ? ResolvePropType<A[]>\n : ResolvePropType<T>\n\ntype IfUnknown<T, V> = [unknown] extends [T] ? V : T\n\nexport type BuildPropOption<T, D extends BuildPropType<T, V, C>, R, V, C> = {\n type?: T\n values?: readonly V[]\n required?: R\n default?: R extends true\n ? never\n : D extends Record<string, unknown> | Array<any>\n ? () => D\n : (() => D) | D\n validator?: ((val: any) => val is C) | ((val: any) => boolean)\n}\n\ntype _BuildPropType<T, V, C> =\n | (T extends PropWrapper<unknown>\n ? T[typeof wrapperKey]\n : [V] extends [never]\n ? ResolvePropTypeWithReadonly<T>\n : never)\n | V\n | C\nexport type BuildPropType<T, V, C> = _BuildPropType<\n IfUnknown<T, never>,\n IfUnknown<V, never>,\n IfUnknown<C, never>\n>\n\ntype _BuildPropDefault<T, D> = [T] extends [\n // eslint-disable-next-line @typescript-eslint/ban-types\n Record<string, unknown> | Array<any> | Function\n]\n ? D\n : D extends () => T\n ? ReturnType<D>\n : D\n\nexport type BuildPropDefault<T, D, R> = R extends true\n ? { readonly default?: undefined }\n : {\n readonly default: Exclude<D, undefined> extends never\n ? undefined\n : Exclude<_BuildPropDefault<T, D>, undefined>\n }\nexport type BuildPropReturn<T, D, R, V, C> = {\n readonly type: PropType<BuildPropType<T, V, C>>\n readonly required: IfUnknown<R, false>\n readonly validator: ((val: unknown) => boolean) | undefined\n [propKey]: true\n} & BuildPropDefault<\n BuildPropType<T, V, C>,\n IfUnknown<D, never>,\n IfUnknown<R, false>\n>\n\n/**\n * @description Build prop. It can better optimize prop types\n * @description 生成 prop能更好地优化类型\n * @example\n // limited options\n // the type will be PropType<'light' | 'dark'>\n buildProp({\n type: String,\n values: ['light', 'dark'],\n } as const)\n * @example\n // limited options and other types\n // the type will be PropType<'small' | 'large' | number>\n buildProp({\n type: [String, Number],\n values: ['small', 'large'],\n validator: (val: unknown): val is number => typeof val === 'number',\n } as const)\n @link see more: https://github.com/element-plus/element-plus/pull/3341\n */\nexport function buildProp<\n T = never,\n D extends BuildPropType<T, V, C> = never,\n R extends boolean = false,\n V = never,\n C = never\n>(\n option: BuildPropOption<T, D, R, V, C>,\n key?: string\n): BuildPropReturn<T, D, R, V, C> {\n // filter native prop type and nested prop, e.g `null`, `undefined` (from `buildProps`)\n if (!isObject(option) || !!option[propKey]) return option as any\n\n const { values, required, default: defaultValue, type, validator } = option\n\n const _validator =\n values || validator\n ? (val: unknown) => {\n let valid = false\n let allowedValues: unknown[] = []\n\n if (values) {\n allowedValues = [...values, defaultValue]\n valid ||= allowedValues.includes(val)\n }\n if (validator) valid ||= validator(val)\n\n if (!valid && allowedValues.length > 0) {\n const allowValuesText = [...new Set(allowedValues)]\n .map((value) => JSON.stringify(value))\n .join(', ')\n warn(\n `Invalid prop: validation failed${\n key ? ` for prop \"${key}\"` : ''\n