Peter Morris
Peter Morris

Reputation: 23284

Is there a way to enforce Generic Constraints based on type rather than duck typing?

The Tester.test() method will compile and run successfully even though SomeQuery1 implements IQueryWithResponse<SomeResponse1> and not iQueryWithResponse<SomeResponse2>

export interface IQueryWithResponse<TResponse> {
}

export class SomeQuery1 implements IQueryWithResponse<SomeResponse1> {
}
export class SomeResponse1 {
}

export class SomeQuery2 implements IQueryWithResponse<SomeResponse2> {
}
export class SomeResponse2 {
}

export class Tester {
  public doRequest<TRequest extends IQueryWithResponse<TResponse>, TResponse>(request: TRequest) : TResponse {
    return null;
  }

  public test() {
    let query = new SomeQuery1();
    let response = this.doRequest<SomeQuery1, SomeResponse2>(query);
  }
}

If this were a language like C# the compiler would throw an error due to the constraint on Tester.doRequest(), but in TypeScript I can pass any type for TResponse as long as it implements the same members as the type I am expecting (which in this example is absolutely anything).

I would like to be able to enforce this generic constraint checking at compile time. Or, at the very least, have a way of ensuring in Tester.doRequest at runtime that request implements IQueryWithResponse<TResponse>

Perhaps there is a way to solve this using meta-data?

Upvotes: 0

Views: 179

Answers (1)

Meirion Hughes
Meirion Hughes

Reputation: 26448

Only way I know of is to have some constant value that differentiates the interfaces. Its technically the same "type" (string) but typescript allows you to be specific about its expected value(s) and will complain if the constant doesn't match.

enter image description here

Its a solution; can't say I like it. :P

Upvotes: 1

Related Questions