0

Generic interface

export interface BaseService {
   getById<T extends number | string>(id: T): Promise<SomeType>;
}

And, the implementation

export class AService implements BaseService {
    async getById(id: number): Promise<SomeType> {
       // logic
    }

    //Other functions will be implemented here
}

And, the error I am getting:

Property 'getById' in type 'AService' is not assignable to the same property in base 
type 'BaseService'.
Type '(id: number) => Promise<SomeType>' is not assignable to type '<T extends 
string | number>(id: T) => Promise<SomeType>'.
Types of parameters 'id' and 'id' are incompatible.
  Type 'T' is not assignable to type 'number'.
    Type 'string | number' is not assignable to type 'number'.
      Type 'string' is not assignable to type 'number'.ts(2416)

Couple of things that I have tried:

getById<T extends number>(id: T): Promise<SomeType>; //This works, But I would have some methods with id type string

And,

getById<T>(id: T): Promise<SomeType>; //still compains

I have been following Documentation. But, haven't encountered any similar thing.

Would really appreciate any ideas or thoughts or any documentation!!

Amjad
  • 330
  • 7
  • 22
  • Why are these methods generic? You don't _use_ the generic type parameter at all, which means they don't need to be generic at all. For example: https://tsplay.dev/wgAnlm – Alex Wayne Jan 28 '23 at 20:34
  • Please [edit] the code to be a self-contained [mre] that demonstrates your issue without unrelated problems when pasted, as-is, into a standalone IDE. For example, errors because `BaseEntity` or `SpeciesEntity` are undefined, should be removed. – jcalz Jan 28 '23 at 20:36
  • @AlexWayne, I am using the id: T which is generic. and Id could be another type – Amjad Jan 28 '23 at 20:40
  • The generic type parameter in `getById(id: T)` let's you capture a type used for the argument `id` and use that type somewhere else, such as the return type of the method. But your return types do not depend on `T` at all. If you don't use `T` anywhere else, then you don't need it, and you're better off using the constraint as the argument type directly. – Alex Wayne Jan 28 '23 at 20:47
  • 1
    Type arguments for generic functions/methods are chosen by the *caller*, not the *implementer*. If you have a value `s` of type `BaseService` (or any type that `extends` it), then you are allowed to call `s.getById("hello")` and `T` will be inferred as `"hello"`. The implementer of `getById()` does not get to decide that `T` will be `number` or anything else. It seems you want `BaseService` itself to be generic in the type of `id`, like [this](https://tsplay.dev/WYRA3w); does that meet your needs? If so I could write up an answer; if not, what am I missing? – jcalz Jan 28 '23 at 20:48
  • This could also an answer. https://stackoverflow.com/questions/17125764/can-you-specify-multiple-type-constraints-for-typescript-generics – Amjad Jan 28 '23 at 20:53

1 Answers1

2

The getById<T extends number | string>(id: T): Promise<SomeType> generic method is pretty pointless, that's more or less equivalent to just declaring a method of type getById(id: number | string): Promise<SomeType>.

I suspect what you actually want is

export interface BaseService<T extends number | string> {
    getById(id: T): Promise<SomeType>;
}
export class AService implements BaseService<number> {
//                                          ^^^^^^^^
    async getById(id: number): Promise<SomeType> {
        …
    }
    …
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • This is an answer. But I have a function that returns service based on a string and because of that I cant have BaseService and Different service could have different T. – Amjad Jan 28 '23 at 20:52
  • You can't, and shouldn't, have a function that returns a service without telling the caller whether it will be a service accepting a number or accepting a string (or both). You can declare it to return a `BaseService` (and then return different services), but that won't be particularly useful. – Bergi Jan 28 '23 at 20:55