chore: update vue-types

pull/2930/head^2
tanjinzhou 2020-09-30 18:14:33 +08:00
parent dbaf8bc7ef
commit f8334fc42a
2 changed files with 36 additions and 24 deletions

View File

@ -1,7 +1,11 @@
import { PropType } from 'vue'; import { PropType } from 'vue';
import isPlainObject from 'lodash-es/isPlainObject'; import isPlainObject from 'lodash-es/isPlainObject';
import { toType, getType, isFunction, validateType, isInteger, isArray, warn } from './utils'; import { toType, getType, isFunction, validateType, isInteger, isArray, warn } from './utils';
interface BaseTypes {
type: any;
def: Function;
validator: Function;
}
const PropTypes = { const PropTypes = {
get any() { get any() {
return toType('any', { return toType('any', {
@ -12,7 +16,7 @@ const PropTypes = {
get func() { get func() {
return { return {
type: Function, type: Function,
}; } as BaseTypes;
}, },
get bool() { get bool() {
@ -63,13 +67,13 @@ const PropTypes = {
}; };
}, },
custom(validatorFn, warnMsg = 'custom validation failed') { custom(validatorFn: Function, warnMsg = 'custom validation failed') {
if (typeof validatorFn !== 'function') { if (typeof validatorFn !== 'function') {
throw new TypeError('[VueTypes error]: You must provide a function as argument'); throw new TypeError('[VueTypes error]: You must provide a function as argument');
} }
return toType(validatorFn.name || '<<anonymous function>>', { return toType(validatorFn.name || '<<anonymous function>>', {
validator(...args) { validator(...args: any[]) {
const valid = validatorFn(...args); const valid = validatorFn(...args);
if (!valid) warn(`${this._vueTypes_name} - ${warnMsg}`); if (!valid) warn(`${this._vueTypes_name} - ${warnMsg}`);
return valid; return valid;
@ -83,14 +87,15 @@ const PropTypes = {
}; };
}, },
oneOf(arr: unknown[]) { oneOf<T extends readonly any[]>(arr: T) {
if (!isArray(arr)) { if (!isArray(arr)) {
throw new TypeError('[VueTypes error]: You must provide an array as argument'); throw new TypeError('[VueTypes error]: You must provide an array as argument');
} }
const msg = `oneOf - value should be one of "${arr.join('", "')}"`; const msg = `oneOf - value should be one of "${arr.join('", "')}"`;
const allowedTypes = arr.reduce((ret, v) => { const allowedTypes = arr.reduce((ret, v) => {
if (v !== null && v !== undefined) { if (v !== null && v !== undefined) {
ret.indexOf(v.constructor) === -1 && ret.push(v.constructor); const constr = (v as any).constructor;
ret.indexOf(constr) === -1 && ret.push(constr);
} }
return ret; return ret;
}, []); }, []);
@ -111,7 +116,7 @@ const PropTypes = {
}; };
}, },
oneOfType(arr) { oneOfType(arr: any[]) {
if (!isArray(arr)) { if (!isArray(arr)) {
throw new TypeError('[VueTypes error]: You must provide an array as argument'); throw new TypeError('[VueTypes error]: You must provide an array as argument');
} }
@ -153,7 +158,7 @@ const PropTypes = {
.reduce((ret, type) => ret.concat(isArray(type) ? type : [type]), []) .reduce((ret, type) => ret.concat(isArray(type) ? type : [type]), [])
.join('", "'); .join('", "');
return this.custom(function oneOfType(value) { return this.custom(function oneOfType(value: any) {
const valid = arr.some(type => { const valid = arr.some(type => {
if (type._vueTypes_name === 'oneOf') { if (type._vueTypes_name === 'oneOf') {
return type.type ? validateType(type.type, value, true) : true; return type.type ? validateType(type.type, value, true) : true;
@ -176,10 +181,10 @@ const PropTypes = {
}); });
}, },
objectOf(type) { objectOf(type: any) {
return toType('objectOf', { return toType('objectOf', {
type: Object as PropType<T>, type: Object,
validator(obj: T): obj is T { validator(obj: { [x: string]: any }) {
const valid = Object.keys(obj).every(key => validateType(type, obj[key])); const valid = Object.keys(obj).every(key => validateType(type, obj[key]));
if (!valid) warn(`objectOf - value must be an object of "${getType(type)}"`); if (!valid) warn(`objectOf - value must be an object of "${getType(type)}"`);
return valid; return valid;
@ -187,13 +192,13 @@ const PropTypes = {
}); });
}, },
shape(obj) { shape(obj: { [x: string]: any; subscribe?: any; setState?: any; getState?: any }) {
const keys = Object.keys(obj); const keys = Object.keys(obj);
const requiredKeys = keys.filter(key => obj[key] && obj[key].required === true); const requiredKeys = keys.filter(key => obj[key] && obj[key].required === true);
const type = toType('shape', { const type = toType('shape', {
type: Object, type: Object,
validator(value) { validator(value: { [x: string]: any }) {
if (!isPlainObject(value)) { if (!isPlainObject(value)) {
return false; return false;
} }
@ -239,7 +244,7 @@ const PropTypes = {
}, },
}; };
const typeDefaults = () => ({ const typeDefaults = (): object => ({
func: undefined, func: undefined,
bool: undefined, bool: undefined,
string: undefined, string: undefined,

View File

@ -7,13 +7,15 @@ export const hasOwn = ObjProto.hasOwnProperty;
const FN_MATCH_REGEXP = /^\s*function (\w+)/; const FN_MATCH_REGEXP = /^\s*function (\w+)/;
// https://github.com/vuejs/vue/blob/dev/src/core/util/props.js#L159 // https://github.com/vuejs/vue/blob/dev/src/core/util/props.js#L159
export const getType = fn => { export const getType = (fn: any) => {
const type = fn !== null && fn !== undefined ? (fn.type ? fn.type : fn) : null; const type = fn !== null && fn !== undefined ? (fn.type ? fn.type : fn) : null;
const match = type && type.toString().match(FN_MATCH_REGEXP); const match = type && type.toString().match(FN_MATCH_REGEXP);
return match && match[1]; return match && match[1];
}; };
export const getNativeType = value => { export const getNativeType = (
value: { constructor: { toString: () => string } } | null | undefined,
) => {
if (value === null || value === undefined) return null; if (value === null || value === undefined) return null;
const match = value.constructor.toString().match(FN_MATCH_REGEXP); const match = value.constructor.toString().match(FN_MATCH_REGEXP);
return match && match[1]; return match && match[1];
@ -22,6 +24,7 @@ export const getNativeType = value => {
/** /**
* No-op function * No-op function
*/ */
// eslint-disable-next-line @typescript-eslint/no-empty-function
export const noop = () => {}; export const noop = () => {};
/** /**
@ -30,7 +33,7 @@ export const noop = () => {};
* @param {object} obj - Object * @param {object} obj - Object
* @param {string} prop - Property to check * @param {string} prop - Property to check
*/ */
export const has = (obj, prop) => hasOwn.call(obj, prop); export const has = (obj: any, prop: any) => hasOwn.call(obj, prop);
/** /**
* Determines whether the passed value is an integer. Uses `Number.isInteger` if available * Determines whether the passed value is an integer. Uses `Number.isInteger` if available
@ -70,9 +73,9 @@ export const isFunction = (value: any) => toString.call(value) === '[object Func
* *
* @param {object} type - Object to enhance * @param {object} type - Object to enhance
*/ */
export const withDefault = function(type) { export const withDefault = function(type: any) {
Object.defineProperty(type, 'def', { Object.defineProperty(type, 'def', {
value(def) { value(def: undefined) {
if (def === undefined && this.default === undefined) { if (def === undefined && this.default === undefined) {
this.default = undefined; this.default = undefined;
return this; return this;
@ -100,7 +103,7 @@ export const withDefault = function(type) {
* *
* @param {object} type - Object to enhance * @param {object} type - Object to enhance
*/ */
export const withRequired = function(type) { export const withRequired = function(type: any) {
Object.defineProperty(type, 'isRequired', { Object.defineProperty(type, 'isRequired', {
get() { get() {
this.required = true; this.required = true;
@ -117,7 +120,7 @@ export const withRequired = function(type) {
* @param {object} obj - Object to enhance * @param {object} obj - Object to enhance
* @returns {object} * @returns {object}
*/ */
export const toType = (name, obj) => { export const toType = (name: string, obj: { type?: any; validator?: any; def?: any }) => {
Object.defineProperty(obj, '_vueTypes_name', { Object.defineProperty(obj, '_vueTypes_name', {
enumerable: false, enumerable: false,
writable: false, writable: false,
@ -140,7 +143,11 @@ export const toType = (name, obj) => {
* @param {boolean} silent - Silence warnings * @param {boolean} silent - Silence warnings
* @returns {boolean} * @returns {boolean}
*/ */
export const validateType = (type, value, silent = false) => { export const validateType = (
type: any,
value: { constructor: { toString: () => string } } | null | undefined,
silent = false,
) => {
let typeToCheck = type; let typeToCheck = type;
let valid = true; let valid = true;
let expectedType; let expectedType;
@ -151,8 +158,8 @@ export const validateType = (type, value, silent = false) => {
if (hasOwn.call(typeToCheck, 'type') && typeToCheck.type !== null) { if (hasOwn.call(typeToCheck, 'type') && typeToCheck.type !== null) {
if (isArray(typeToCheck.type)) { if (isArray(typeToCheck.type)) {
valid = typeToCheck.type.some(type => validateType(type, value, true)); valid = typeToCheck.type.some((type: any) => validateType(type, value, true));
expectedType = typeToCheck.type.map(type => getType(type)).join(' or '); expectedType = typeToCheck.type.map((type: any) => getType(type)).join(' or ');
} else { } else {
expectedType = getType(typeToCheck); expectedType = getType(typeToCheck);