clencat
clencat

Reputation: 159

Why do I get an error in Typescript when I use a generic as a return value?

My code looks like this

const fn = <T extends (object | any[])>(foo: T): T => {
  if(Array.isArray(foo)){
    return foo.map(item=>item)   // <--- error
  } else {
    return foo
  }
}

Type 'any[]' is not assignable to type 'T'. 'any[]' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'object | any[]'.(2322)

I don't know why the error is reported. Can anyone help me?

Upvotes: 0

Views: 396

Answers (1)

Radu Diță
Radu Diță

Reputation: 14191

The problem stems from the fact that your function claims it will return an object of type T, but in fact you could be returning a type that's narrower (a subtype) of T.

To see why this could be a problem look over this example

const fn = <T extends (object | any[])>(foo: T): T => {
  if(Array.isArray(foo)){
    return {}
  } else {
    return foo
  }
}

This will give you the exact same error, but I think we can both agree that if I pass an array I would expect an array back. But just looking at that function I could be returning an empty object.

The problem arrises when you have more properties on the type than you are returning. Imagine you pass in an array that has some other properties on it. Doing the map will erase those properties but the caller would expect them to be present.

What you can do is that you can use a cast, but this is unsound. (So you shouldn't do it)

const fn = <T extends (object | any[])>(foo: T): T => {
  if(Array.isArray(foo)){
    return foo.map(item=>item) as any
  } else {
    return foo
  }
}

Upvotes: 1

Related Questions