简体   繁体   中英

TypeScript Convert Enum to another Emum with GraphQL generated types

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?

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();
  });
}); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM