sschmeck
sschmeck

Reputation: 7715

Convert string parameter to an array of one element

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

Answers (5)

Shidersz
Shidersz

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

RedGuy11
RedGuy11

Reputation: 381

Short solution:

[names].flat()

If names is an array, it will be left as-is. Anything else will be converted to an array with one element.

Demo

Demo

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.

Alternative

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

Nina Scholz
Nina Scholz

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

Eric Duminil
Eric Duminil

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

Ori Drori
Ori Drori

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

Related Questions