Reputation: 7715
I wrote a function which has to support two types of a paramter names
for a list of values. Internally it deals with the parameter as an array.
A single name is given as string and multiples names are given as an array of strings.
// simplified example
let doSome = names => names.map(name => name.toUpperCase())
names(['Bart', 'Lisa'])
// [ 'BART', 'LISA' ]
names('Homer')
// TypeError: names.map is not a function
I found a solution using Array.of()
in combination with flatten()
which needs some babel configuration.
doSome = names => Array.of(names).flatten().map(name => name.toUpperCase());
Is there an idiomatic way in JavaScript to get an array without a type check?
Upvotes: 28
Views: 12348
Reputation: 17190
Why not just check if the input is an array or not using isArray()?
I made another solution using this approach, also I put a control inside the map()
so this don't fail when the name
argument is null
or undefined
.
const names = x => (Array.isArray(x) ? x : [x]).map(name => name && name.toUpperCase());
console.log(JSON.stringify( names(['Bart', 'Lisa']) ));
console.log(JSON.stringify( names('Homer') ));
console.log(JSON.stringify( names('') ));
console.log(JSON.stringify( names(null) ));
console.log(JSON.stringify( names([null]) ));
console.log(JSON.stringify( names([undefined, "Roger", "Bob", null]) ));
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}
Upvotes: 3
Reputation: 381
[names].flat()
If names
is an array, it will be left as-is. Anything else will be converted to an array with one element.
This works because .flat()
only flattens one level by default.
If names
is not an array, [names]
makes it an array with one element, and .flat()
does nothing more because the array has no child arrays.
If names
is an array, [names]
makes it an array with one child array, and .flat()
brings the child array back up to be a parent array.
This is more self-explanitory:
names instanceof Array ? names : [names]
This uses a simple ternary statement to do nothing to it if it is an array already or make it an array if it is not already.
Upvotes: 10
Reputation: 386868
Maybe an maybe upcoming method of Array#flat
would help in this case (works actually only in Chrome and FF).
const names = unknown => [unknown].flat().map(name => name.toUpperCase())
console.log(names(['Bart', 'Lisa']));
console.log(names('Homer'));
Upvotes: 2
Reputation: 54303
You might not be able to implement it this way if you already have code depending on this function. Still, it would probably be cleaner to allow your function to accept a variable number of arguments with rest parameters.
It means you can call the function as names('Homer')
or names('Bart', 'Lisa')
:
function names(...args){
return args.map(name => name.toUpperCase());
}
console.log(names('Bart', 'Lisa')); // [ 'BART', 'LISA' ]
console.log(names('Homer')); // ['HOMER']
If you really want to call the function with an array as argument, you can use the spread syntax :
console.log(names(...['Bart', 'Lisa'])); // [ "BART", "LISA" ]
If you use it with a string, you'll get back an array of characters, though:
console.log(names(...'Homer')); // [ "H", "O", "M", "E", "R" ]
Upvotes: 2
Reputation: 193250
You can use Array.concat()
, since concat accepts both arrays and non arrays:
const names = (v) => [].concat(v).map(name => name.toUpperCase())
console.log(names(['Bart', 'Lisa'])) // [ 'BART', 'LISA' ]
console.log(names('Homer')) // ['HOMER']
Upvotes: 32