dkthehuman
dkthehuman

Reputation: 294

Why does this type guard not work on generic parameters?

Consider the following code (TS Playground):

function identity<T>(value: T): T {
  if (typeof value === 'string') {
    return value.replace('foo', 'bar'); // <-- ERROR
  }
  return value;
}

It results in the error Type 'string' is not assignable to type 'T'. 'T' could be instantiated with an arbitrary type which could be unrelated to 'string'.

It seems that the type guard is not sufficient to narrow the type of the generic parameter and perform a string operation.

Why does this error occur and how would I resolve it?

Upvotes: 0

Views: 440

Answers (1)

Nicholas Tower
Nicholas Tower

Reputation: 84912

Suppose the function gets called like this

const example: 'foo' = 'foo';

const result = identity(example);

According to the type definition of the function, since T is "foo" (ie, a specific string, not a general string), i must be returned a "foo" as well. But the code inside the function will return "bar" instead, so it's violating the types.


To do what you want, you'll want to use function overloading to give it different types for the string case than for other cases. For example:

function identity<T>(value: string): string;
function identity<T>(value: T): T;
function identity<T>(value: T): T | string {
  if (typeof value === 'string') {
    return value.replace('foo', 'bar');
  }
  return value;
}

If this code is called with T == "foo", then typescript will see that a value of "foo" is compatible with value: string, so the first type definition for the function matches. According to that type definition, the return value is thus a general string.

Playground link

Upvotes: 1

Related Questions