I have an enum for http methods:
export enum HttpMethod {
  GET = 'GET', POST = 'POST', /*...*/
}
Then I define a basic method type, that can have any HttpMethod as key:
type Methods = {
  [M in HttpMethod]?: any;
};
A basic Route type could use this Method type:
type Route<M extends Methods = any> = {
  methods: M;
}
So I can define any route like:
interface AnyRoute extends Route<{
  [HttpMethod.GET]: AnyRequestHandler;
}> {}
So far so good. Now I want to add a Validator:
type Validator<R extends Route, M extends HttpMethod> = {/*...*/}
And only want to allow adding Methods to the Validator, that are defined in the Route:
type RouteMethodValidators<R extends Route> = {
  [M in keyof R['methods']]?: Validator<R, M>;
};
Although my IDE seems to understand it, I get the following errors:
Type 'M' does not satisfy the constrain 'HttpMethod'. Type 'keyof R["methods"]' is not assignable to type 'HttpMethod'.Is there any way I can tell typescript, that this is is definitely a member of HttpMethod?
Your problem mostly lies here: type Route<M extends Methods = any>
First of all, a default value any will result in M being of type string in RouteMethodValidator because Route<any>['methods'] is any and keyof any is string.
Now, changing the default value to Methods still won't solve the problem because you do M extends Methods which basically means that M can have more keys than the ones defined in Methods, i.e. more than are defined in HttpMethods. But in Validator you only allow values of HttpMethods.
I believe your best option would be to make Route not generic.
type Route = {
  methods: Methods;
}
type RouteMethodValidators<R extends Route> = {
  [M in HttpMethod]?: Validator<R, M>;
}
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With