0

My issue is converting a type of object generated by GraphQL schema to another one that's more compact for other purposes.

The issue is that trying to move from enum that is generated for GraphQL to enum that is for the desired DTO I'v accounted the following error:

import type { Pets as GqlPets, GqlPerson } from 'gql/types';

enum Pets {
  cat = "Cat";
  dog = "Dog";
};

type Person = { 
  name: string;
  email: string;
  pet: Pets;
}

function gqlPersonToJson(p: GqlPerson): Person {
  return {
    name: p.name,
    email: p.email,
    pet: p.pet, //--> error Type 'GqlPets' is not assignable to type 'Pets'.
  };
}

When I try to convert the enum I get the following error:

pet: GqlPerson[p.pet] as keyof typeof Pets,

Error:

TS2322: Type '"cat" | "dog"' is not assignable to type 'Pets'.   Type '"cat"' is not assignable to type 'Pets'. Did you mean 'Pets.cat'?

What Am I missing?

1 Answer 1

2

You need to have the following function that ensures for the typescript compiler that the values are "assignable".

This solution is based on the assumption you want the enum values to be the same, the enum keys can be different:


enum Pets {
  cat = "Cat";
  dog = "Dog";
};

enum JqlPets {
  kitten = "Cat"; //keys are not required to be the same, only the values
  doggy = "Dog";
};

Solution based on that limitation

const canBeConvertedToPet = (value: any): value is Pet => {
  return Object.values(Pet).some((v) => v === value);
}

function gqlPersonToJson(p: GqlPerson): Person {
  if (!canBeConvertedToPet(p.pet)) {
    throw new Error(`Not mapped Pet value ${p.pet}`);
  }
  return {
    name: p.name,
    email: p.email,
    pet: p.pet,
  };
}

The drawback is that If you add a value to the jqlPet, which does not exist in the Pet enum - it will throw an error runtime, not compile time. This can be solved by writing a unit test, and run the test as part of PR acceptance pipeline

import type { Pets as GqlPets, GqlPerson } from 'gql/types';
import type { Pet, canBeConvertedToPet } from '............';

it("Should have Pet mapping for each GqlPet value", () => {
  const allJqlValues = Object.values(GqlPets);
  allJqlValues.forEach((gqlValue) => {
    expect(canBeConvertedToPet(gqlValue)).toBeTruthy();
  });
}); 
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.