Have been working on adding an abstract class to support versioning for Resolvers for a floorPlan feature and was wondering how I might fix this error. At the moment I do not get any Type errors but when the code compiles NestJs throws this error:
Undefined type error. Make sure you are providing an explicit type for the "floorPlanUpdate" (parameter at index [2]) of the "BaseResolverHost" class.
In a normal resolver this is not a problem as you pass in the type e.g.:
@Args('input') input: UpdateFloorPlanV1Input,
However as I am trying to determine the input type based off the version of the Floorplan using this line:
@Args('input') input: UpdateFloorPlanVersion<FloorPlanVersion>,
So it is not possible to explicitly declare it here. Let me know if this is possible or if anyone has any other approaches
This is the abstract Resolver code:
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
import { UserId } from 'src/users/decorators/user-id.decorator';
import { CreateFloorPlanInput } from './v1/dto/create-floor-plan.input';
import { UpdateFloorPlanV1Input } from './v1/dto/update-floor-plan.input';
import { FloorPlanV1 } from './v1/models/floor-plan.model';
import { UpdateFloorPlanV2Input } from './v2/dto/update-floor-plan.input';
import { FloorPlanV2 } from './v2/models/floor-plan.model';
export type FloorPlanVersion = FloorPlanV1 | FloorPlanV2;
export type UpdateFloorPlanVersion<T extends FloorPlanVersion> =
T extends FloorPlanV1 ? UpdateFloorPlanV1Input : UpdateFloorPlanV2Input;
export interface FloorPlanServiceInterface<FloorPlanVersion> {
create(
userId: string,
createFloorPlanInput: CreateFloorPlanInput,
): Promise<FloorPlanVersion>;
findOne(userId: string, floorPlanId: string): Promise<FloorPlanVersion>;
update(
userId: string,
floorPlanId: string,
input: UpdateFloorPlanV1Input,
): Promise<FloorPlanVersion>;
}
export function BaseResolver<T extends Type<FloorPlanVersion>>(
classRef: T,
version: string,
) {
@Resolver({ isAbstract: true })
abstract class BaseResolverHost {
floorPlanService: FloorPlanServiceInterface<FloorPlanVersion>;
constructor(readonly service: FloorPlanServiceInterface<FloorPlanVersion>) {
this.floorPlanService = service;
}
@Mutation(() => classRef, { name: `floorPlanCreate${version}` })
async floorPlanCreate(
@UserId() userId,
@Args('input')
input: CreateFloorPlanInput,
) {
return this.floorPlanService.create(userId, input);
}
@Query(() => classRef, { name: `floorPlan${version}` })
async floorPlan(@UserId() userId, @Args('id') id: string) {
return this.floorPlanService.findOne(userId, id);
}
@Mutation(() => classRef, { name: `floorPlanUpdate${version}` })
async floorPlanUpdate(
@UserId() userId,
@Args('id') id: string,
@Args('input') input: UpdateFloorPlanVersion<FloorPlanVersion>,
) {
return this.floorPlanService.update(userId, id, input);
}
}
return BaseResolverHost;
}
And then it is called like this:
@Resolver(() => FloorPlanV2)
export class FloorPlanV2Resolver extends BaseResolver(FloorPlanV2, 'V2') {
constructor(
readonly floorPlanService: FloorPlanService,
) {
super(floorPlanService);
}
}
So if the ObjectType was FloorPlanV2 we would expect the UpdateFloorPlanInputType to be UpdateFloorPlanV2Input