Skip to content

Commit d97d20e

Browse files
author
Eduardo Alves
committed
feature: allow component prop type to be an array of types
1 parent 25e4995 commit d97d20e

File tree

2 files changed

+84
-27
lines changed

2 files changed

+84
-27
lines changed

src/compiler/compile-props.js

Lines changed: 51 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -278,36 +278,23 @@ export function assertProp (prop, value) {
278278
}
279279
var options = prop.options
280280
var type = options.type
281-
var valid = true
282-
var expectedType
281+
var valid
282+
var expectedTypes = []
283283
if (type) {
284-
if (type === String) {
285-
expectedType = 'string'
286-
valid = typeof value === expectedType
287-
} else if (type === Number) {
288-
expectedType = 'number'
289-
valid = typeof value === 'number'
290-
} else if (type === Boolean) {
291-
expectedType = 'boolean'
292-
valid = typeof value === 'boolean'
293-
} else if (type === Function) {
294-
expectedType = 'function'
295-
valid = typeof value === 'function'
296-
} else if (type === Object) {
297-
expectedType = 'object'
298-
valid = isPlainObject(value)
299-
} else if (type === Array) {
300-
expectedType = 'array'
301-
valid = isArray(value)
302-
} else {
303-
valid = value instanceof type
284+
if (!isArray(type)) {
285+
type = [ type ]
286+
}
287+
for (var i = 0; i < type.length && !valid; i++) {
288+
var assertedType = assertType(value, type[i])
289+
expectedTypes.push(assertedType.expectedType)
290+
valid = assertedType.valid
304291
}
305292
}
306-
if (!valid) {
293+
if (typeof valid !== 'undefined' && !valid) {
307294
process.env.NODE_ENV !== 'production' && warn(
308295
'Invalid prop: type check failed for ' +
309296
prop.path + '="' + prop.raw + '".' +
310-
' Expected ' + formatType(expectedType) +
297+
' Expected ' + formatTypes(expectedTypes) +
311298
', got ' + formatValue(value) + '.'
312299
)
313300
return false
@@ -342,9 +329,46 @@ export function coerceProp (prop, value) {
342329
return coerce(value)
343330
}
344331

345-
function formatType (val) {
346-
return val
347-
? val.charAt(0).toUpperCase() + val.slice(1)
332+
function assertType (value, type) {
333+
var valid
334+
var expectedType
335+
if (type === String) {
336+
expectedType = 'string'
337+
valid = typeof value === expectedType
338+
} else if (type === Number) {
339+
expectedType = 'number'
340+
valid = typeof value === expectedType
341+
} else if (type === Boolean) {
342+
expectedType = 'boolean'
343+
valid = typeof value === expectedType
344+
} else if (type === Function) {
345+
expectedType = 'function'
346+
valid = typeof value === expectedType
347+
} else if (type === Object) {
348+
expectedType = 'object'
349+
valid = isPlainObject(value)
350+
} else if (type === Array) {
351+
expectedType = 'array'
352+
valid = isArray(value)
353+
} else {
354+
valid = value instanceof type
355+
}
356+
return {
357+
valid,
358+
expectedType
359+
}
360+
}
361+
362+
function formatTypes (types) {
363+
return types.reduce(
364+
(p, c, i) => { return i === 0 ? formatType(c) : `${p}, ${formatType(c)}` },
365+
''
366+
)
367+
}
368+
369+
function formatType (type) {
370+
return type
371+
? type.charAt(0).toUpperCase() + type.slice(1)
348372
: 'custom type'
349373
}
350374

test/unit/specs/directives/internal/prop_spec.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,13 @@ describe('prop', function () {
364364
expect('Expected custom type').toHaveBeenWarned()
365365
})
366366

367+
it('multiple types', function () {
368+
makeInstance([], [Array, Number, Boolean])
369+
expect(getWarnCount()).toBe(0)
370+
makeInstance({}, [Array, Number, Boolean])
371+
expect('Expected Array, Number, Boolean').toHaveBeenWarned()
372+
})
373+
367374
it('custom validator', function () {
368375
makeInstance(123, null, function (v) {
369376
return v === 123
@@ -390,6 +397,21 @@ describe('prop', function () {
390397
expect('Expected String').toHaveBeenWarned()
391398
})
392399

400+
it('multiple types + custom validator', function () {
401+
makeInstance(123, [Number, String, Boolean], function (v) {
402+
return v === 123
403+
})
404+
expect(getWarnCount()).toBe(0)
405+
makeInstance(123, [Number, String, Boolean], function (v) {
406+
return v === 234
407+
})
408+
expect('custom validator check failed').toHaveBeenWarned()
409+
makeInstance(123, [String, Boolean], function (v) {
410+
return v === 123
411+
})
412+
expect('Expected String, Boolean').toHaveBeenWarned()
413+
})
414+
393415
it('type check + coerce', function () {
394416
makeInstance(123, String, null, String)
395417
expect(getWarnCount()).toBe(0)
@@ -401,6 +423,17 @@ describe('prop', function () {
401423
expect(getWarnCount()).toBe(0)
402424
})
403425

426+
it('multiple types + custom validator', function () {
427+
makeInstance(123, [String, Boolean, Number], null, String)
428+
expect(getWarnCount()).toBe(0)
429+
makeInstance('123', [String, Boolean, Number], null, Number)
430+
expect(getWarnCount()).toBe(0)
431+
makeInstance('123', [String, Boolean, Function], null, function (val) {
432+
return val === '123'
433+
})
434+
expect(getWarnCount()).toBe(0)
435+
})
436+
404437
it('required', function () {
405438
new Vue({
406439
el: document.createElement('div'),

0 commit comments

Comments
 (0)