Generic type but exclude array types

Viewed 380

If I have a function that takes any type and returns it, how can I ensure the function won't accept an array type? I want to accept all types except arrays.

function someFunc<T>(arg: T): T { return arg; }

This should be valid:

someFunc('string');

But this should fail:

someFunc(['string', 'string2']);

Is it possible?

2 Answers

You can do something like this:

function someFunc<T>(arg: Exclude<T, any[]>): T { return arg; }

someFunc('string'); // OK

// Argument of type 'never[]' is not assignable to parameter of type 'never'.ts(2345)
// ^ Error appears on the whole array
someFunc<any[]>([]);

// Type 'string' is not assignable to type 'never'.ts(2322)
// ^ Error appears on each array element
someFunc<any[]>(['string', 'string2']);

// Argument of type 'never[]' is not assignable to parameter of type 'never'.ts(2345)
// ^ Error appears on the whole array
someFunc([]);

// Type 'string' is not assignable to type 'never'.ts(2322)
// ^ Error appears on each array element
someFunc(['string', 'string2']);

// Type 'string' is not assignable to type 'never'.ts(2322)
// ^ Error appears on each array element
someFunc<string[]>(['string', 'string2']);

The errors it produces are a little bit unexpected, but they're there.

Best solution: use Exclude

Kelvin's answer seems to be the best fit for the question. I proposed the following solution before I saw his response:

Solution 1: Return never

In line with the other answer already given, return never if the given type is an array. This will not give a compiler error when calling the function, but the user cannot do anything with the returned value.

function someFunc<T>(arg: T): T extends any[] ? never : T {
  return arg as any; // need cast to satisfy compiler
}

const a = someFunc("");
// type of a: string

const b = someFunc([1]);
// no compiler error, but type of b: never

Solution 2: Exclude random method only available on arrays

You can take some random method that is only available on the type you want to exclude. Here I take the push method:

function someFunc<T>(arg: T & { push?: never }): T {
  return arg;
}

someFunc(""); // no problem
someFunc([1]); // compiler error
Related