Search code examples
javascripttypescriptgraphqlnestjsbackend

How can I resolve signature of method decorator when called as an expression?


I am getting the following error when writing the @Query Decorator for getAccountAssets resolver method:-

Unable to resolve signature of method decorator when called as an expression. Argument of type 'TypedPropertyDescriptor<(userTokenPayload: UserTokenPayload, accountType: AccountType) => Promise>' is not assignable to parameter of type 'number'.ts(1241) No overload matches this call. Overload 1 of 3, '(...pipes: (PipeTransform<any, any> | Type<PipeTransform<any, any>>)[]): ParameterDecorator', gave the following error. Argument of type '() => typeof AllAccountAssetsResponse' is not assignable to parameter of type 'PipeTransform<any, any> | Type<PipeTransform<any, any>>'. Overload 2 of 3, '(property: string, ...pipes: (PipeTransform<any, any> | Type<PipeTransform<any, any>>)[]): ParameterDecorator', gave the following error. Argument of type '() => typeof AllAccountAssetsResponse' is not assignable to parameter of type 'string'.ts(2769)

import { CustomerService } from '@app/customers/customers.service';
import { CurrentUserTokenPayload } from '@auth/decorators';
import { UserTokenPayload } from '@auth/dto/auth.interfaces';
import { GqlAuthGuard } from '@auth/guards';
import { Query, UseGuards } from '@nestjs/common';
import {
  Args, Mutation, Resolver,
} from '@nestjs/graphql';

import { AccountType } from './dto/accounts.interfaces';
import {
  UpdateThirdPartyFundingInfoInput,
} from './dto/common-account.input';
import {
  AccountResponse, AllAccountAssetsResponse,
} from './dto/common-account.response';
import { OpportunityAccountsService } from './opportunity-accounts.service';
import { StandardAccountsService } from './standard-accounts.service';

@Resolver(() => AccountResponse)
export class CommonAccountResolver {
  constructor(
    private readonly standardAccountsService: StandardAccountsService,
    private readonly opportunityAccountsService: OpportunityAccountsService,
    private readonly customerService: CustomerService,
  ) { }

  async getAccountServiceByType(params: {
    accountType: AccountType; userId: string;
  }) {
    const { accountType, userId } = params;
    const {
      customerId,
      resourceRelationships: { standardAccountId, opportunityAccountId },
    } = await this.customerService.validateCustomerRelationship({ userId });
    return {
      [AccountType.OPPORTUNITY]: {
        accountService: this.opportunityAccountsService,
        accountId: opportunityAccountId,
        customerId,
      },
      [AccountType.STANDARD]: {
        accountService: this.standardAccountsService,
        accountId: standardAccountId,
        customerId,
      },
    }[accountType];
  }



  @UseGuards(GqlAuthGuard)
  @Query(() => AllAccountAssetsResponse) // error is happening here
  async getAccountAssets(
    @CurrentUserTokenPayload() userTokenPayload: UserTokenPayload,
    @Args('accountType', { type: () => AccountType }) accountType: AccountType,
  ) : Promise<AllAccountAssetsResponse> {
    const { accountId, accountService } = await this.getAccountServiceByType({
      accountType, userId: userTokenPayload.sub,
    });

    const accountAssetDetails = await accountService.getAccountAssets({
      accountId,
    });
    return accountAssetDetails;
  }
}

response.ts :-

import {
  createUnionType, Field, ObjectType,
  registerEnumType,
} from '@nestjs/graphql';
import { Type } from 'class-transformer';
import { IsArray } from 'class-validator';

import { AssetStatus, ProductType } from '@/generated-cbms-api-client';

import { AccountType } from './accounts.interfaces';
import { OpportunityAccount } from './opportunity-account.response';
import { StandardAccount } from './standard-account.response';

registerEnumType(AssetStatus, { name: 'AssetStatus' });
registerEnumType(ProductType, { name: 'ProductType' });

export const AccountDetails = createUnionType({
  name: 'AccountDetails',
  types: () => [OpportunityAccount, StandardAccount] as const,
  resolveType:
    (accountDetails) => {
      if ('accountPurpose' in accountDetails) {
        return StandardAccount;
      }
      return OpportunityAccount;
    },
});

@ObjectType()
export class AccountResponse {
  @Field(() => AccountType)
  accountType: AccountType;

  @Field(() => AccountDetails)
  accountDetails: OpportunityAccount | StandardAccount;
}

@ObjectType()
export class AccountAssetResponse {
  @Field(() => AssetStatus)
  status: AssetStatus;

  @Field(() => ProductType)
  productType: ProductType;

  @Field(() => String)
  createdAt?: string;

  @Field(() => String)
  updatedAt?: string;

  @Field(() => String)
  assetTypeId: string;

  @Field(() => String)
  productId: string;

  @Field(() => String)
  customerId: string;

  @Field(() => String)
  currentBalance: string;

  @Field(() => String)
  availableBalance: string;

  @Field(() => String)
  parentAccountId: string;
}

@ObjectType()
export class AllAccountAssetsResponse {
  @IsArray()
  @Type(() => AccountAssetResponse)
  @Field(() => [AccountAssetResponse], { description: 'Expected investment support info' })
  accountAssets: AccountAssetResponse[];

  @Field(() => String)
  nextCursor: string;

  @Field(() => Boolean)
  hasMore: boolean;

  @Field(() => Number)
  totalCount: number;
}

I don't know what I am missing. The Response of accountService.getAccountAssets also conforms to Promise<AllAccountAssetsResponse>.


Solution

  • You made a mistake when importing Query:

    import { Query, UseGuards } from '@nestjs/common'
    

    You need to import it from @nestjs/graphql:

    import { Query } from '@nestjs/graphql';
    

    Here is a file from nestjs' sample repository that imports Query.