[SOLVED] Using generics for classes with and without an array: Type ‘string’ does not satisfy the constraint ‘string[]’

Issue

This Content is from Stack Overflow. Question asked by Country29

I have a simple interface:

interface Animal<T> {
  isMatch: (value: T) => boolean
}

with these implementations:

class Dog implements Animal<string> {
  isMatch(input: string): boolean {
    // do something with string
  }
}

and

class Cat<T extends T[]> implements Animal<T> {
  isMatch(input: T[]): boolean {
    // do something with list
  }
}

I can instantiate a Dog without issue with:

const dog = new Dog("pug")

However, I can’t instantiate a Cat with any of:

const cat = new Cat<string>(...) // Type 'string' does not satisfy the constraint 'string[]'

const cat = new Cat<string[]>(...) // Type 'string[]' does not satisfy the constraint 'string[][]'

const cat = new Cat(["birman"]) // Type 'string' does not satisfy the constraint 'string[]'

I’ve used the generics / extends based on examples I’ve seen online, so not sure what I’m misunderstanding here.



Solution

I understand why you used T extends T[], because of this error when you don’t:

Type ‘T’ is not assignable to type ‘T[]’.(2416)

input.tsx(11, 11): This type parameter might need an extends T[]
constraint.

This error is misleading in this case, but if we think through what we want, we can get the solution.

You want isMatch to take the type T[]. However, Cat only takes T. Remember that isMatch is defined by the interface Animal, and in the interface, it takes T (in the interface). If we want these types to match, we just have to make Animal take T[]!

class Cat<T> implements Animal<T[]> {

And that’s it.

Playground


This Question was asked in StackOverflow by Country29 and Answered by caTS It is licensed under the terms of CC BY-SA 2.5. - CC BY-SA 3.0. - CC BY-SA 4.0.

people found this article helpful. What about you?