'TS: How to ensure generic type on Express Response
I have an interface that has a method The method has a parameter The parameter has a type that takes a generic The method has a return, which also receives a generic A class implements my interface, and therefore implements the method I need to ensure that:
- The method parameter can only receive a type that receives the same generic defined in the interface;
- The method return can only receive a type that receives the same generic defined in the interface;
- In the interface, I just need to declare the type in the parameter, and use the same type inside a Promise in the return; This one is desired, but not required.
Straight to the code:
import { Request, Response } from 'express';
interface Foo {
foo: string;
}
interface Bar {
bar: string;
}
interface Controller<T> {
create: (
req: Request, // not important to the question
res: Response<T | Bar>
) => Promise<Response<T | Bar>>;
}
The code below works fine:
class MyController1 implements Controller<Foo> {
create = async (
_req: Request,
res: Response<Foo | Bar>
): Promise<Response<Foo | Bar>> =>
res.json({ bar: 'bar' });
}
And if I try, for example, to remove the Bar option in the return type, the TS Compiler complains (and it is okay):
class MyController2 implements Controller<Foo> {
create = async ( // Error on this line, incorrect property
_req: Request,
res: Response<Foo | Bar>
): Promise<Response<Foo>> => // I can't remove the `Bar` option
res.json({ bar: 'bar' });
}
However, if I remove the type of the Response (both in return type and in res type), i get no TS Compiler errors:
class MyController3 implements Controller<Foo> {
create = async (
_req: Request,
res: Response, // Removed response type
): Promise<Response> =>
res.json({ ahdiashda: 'string' }); // Not `foo` nor `bar`, but no TS error
}
How can I create an interface Controller that, when implemented, it ensures the method' signature, so I can have something like (or the close as possible to):
// SOLUTION 1
class MyController4 implements Controller<Foo> {
create = async (_req, res) => // I want no error because of lack of type on parameters
res.json({ ahdiashda: 'string' }); // I want an error because it's not `Foo` nor `Bar`
}
class MyController5 implements Controller<Foo> {
create = async (_req, res) =>
res.json({ foo: 'string' }); // I want NO error
}
// OR SOLUTION 2
class MyController6 implements Controller<Foo> {
create = async (_req: Request, res: Response) =>
res.json({ ahdiashda: 'string' }); // I want an error because it's not `Foo` nor `Bar`
}
class MyController7 implements Controller<Foo> {
create = async (_req: Request, res: Response) =>
res.json({ foo: 'string' }); // I want NO error
}
SOLUTION 3: you have another class implementation idea on how to implements the same controller interface, ensuring the types but with no code duplication?
PS:
The problem with MyController1 is that I have to repeat the type of res and the return value. If I create some 10 or 20 Controllers, if the interface changes, I will have to update the types in 10 or 20 places, violating the DRY.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
