From 9f27fedd84acbd1e4bc7a89d16318a2ac4968711 Mon Sep 17 00:00:00 2001 From: Ivan Goncharov Date: Mon, 5 Mar 2018 14:55:55 +0200 Subject: [PATCH 1/3] Switch SW API example to SDL --- src/__tests__/starWarsData.js | 27 +- src/__tests__/starWarsQuery-test.js | 225 ++++++--------- src/__tests__/starWarsSchema.js | 424 ++++++++++------------------ 3 files changed, 250 insertions(+), 426 deletions(-) diff --git a/src/__tests__/starWarsData.js b/src/__tests__/starWarsData.js index 1c2b848ed9..07e95dd5d7 100644 --- a/src/__tests__/starWarsData.js +++ b/src/__tests__/starWarsData.js @@ -93,14 +93,9 @@ const droidData = { * These are Flow types which correspond to the schema. * They represent the shape of the data visited during field resolution. */ -export type Character = { - id: string, - name: string, - friends: Array, - appearsIn: Array, -}; +export type CharacterData = HumanData | DroidData; -export type Human = { +export type HumanData = { type: 'Human', id: string, name: string, @@ -109,7 +104,7 @@ export type Human = { homePlanet: string, }; -export type Droid = { +export type DroidData = { type: 'Droid', id: string, name: string, @@ -121,23 +116,15 @@ export type Droid = { /** * Helper function to get a character by ID. */ -function getCharacter(id) { +export function getCharacter(id: string): Promise { // Returning a promise just to illustrate GraphQL.js's support. return Promise.resolve(humanData[id] || droidData[id]); } -/** - * Allows us to query for a character's friends. - */ -export function getFriends(character: Character): Array> { - // Notice that GraphQL accepts Arrays of Promises. - return character.friends.map(id => getCharacter(id)); -} - /** * Allows us to fetch the undisputed hero of the Star Wars trilogy, R2-D2. */ -export function getHero(episode: number): Character { +export function getHero(episode: number): CharacterData { if (episode === 5) { // Luke is the hero of Episode V. return luke; @@ -149,13 +136,13 @@ export function getHero(episode: number): Character { /** * Allows us to query for the human with the given id. */ -export function getHuman(id: string): Human { +export function getHuman(id: string): HumanData { return humanData[id]; } /** * Allows us to query for the droid with the given id. */ -export function getDroid(id: string): Droid { +export function getDroid(id: string): DroidData { return droidData[id]; } diff --git a/src/__tests__/starWarsQuery-test.js b/src/__tests__/starWarsQuery-test.js index 6ae55b22a1..cdac1eadb9 100644 --- a/src/__tests__/starWarsQuery-test.js +++ b/src/__tests__/starWarsQuery-test.js @@ -9,53 +9,50 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import { StarWarsSchema } from './starWarsSchema'; +import { StarWarsSchema, Query } from './starWarsSchema'; import { graphql } from '../graphql'; +function executeQuery(query, variableValues) { + return graphql(StarWarsSchema, query, new Query(), null, variableValues); +} + describe('Star Wars Query Tests', () => { describe('Basic Queries', () => { it('Correctly identifies R2-D2 as the hero of the Star Wars Saga', async () => { - const query = ` - query HeroNameQuery { + const result = await executeQuery(` + { hero { name } } - `; - const result = await graphql(StarWarsSchema, query); + `); + expect(result).to.deep.equal({ data: { - hero: { - name: 'R2-D2', - }, + hero: { name: 'R2-D2' }, }, }); }); it('Accepts an object with named properties to graphql()', async () => { - const query = ` - query HeroNameQuery { + const result = await executeQuery(` + { hero { name } } - `; - const result = await graphql({ - schema: StarWarsSchema, - source: query, - }); + `); + expect(result).to.deep.equal({ data: { - hero: { - name: 'R2-D2', - }, + hero: { name: 'R2-D2' }, }, }); }); it('Allows us to query for the ID and friends of R2-D2', async () => { - const query = ` - query HeroNameAndFriendsQuery { + const result = await executeQuery(` + { hero { id name @@ -64,23 +61,17 @@ describe('Star Wars Query Tests', () => { } } } - `; - const result = await graphql(StarWarsSchema, query); + `); + expect(result).to.deep.equal({ data: { hero: { id: '2001', name: 'R2-D2', friends: [ - { - name: 'Luke Skywalker', - }, - { - name: 'Han Solo', - }, - { - name: 'Leia Organa', - }, + { name: 'Luke Skywalker' }, + { name: 'Han Solo' }, + { name: 'Leia Organa' }, ], }, }, @@ -90,8 +81,8 @@ describe('Star Wars Query Tests', () => { describe('Nested Queries', () => { it('Allows us to query for the friends of friends of R2-D2', async () => { - const query = ` - query NestedQuery { + const result = await executeQuery(` + { hero { name friends { @@ -103,8 +94,8 @@ describe('Star Wars Query Tests', () => { } } } - `; - const result = await graphql(StarWarsSchema, query); + `); + expect(result).to.deep.equal({ data: { hero: { @@ -114,51 +105,29 @@ describe('Star Wars Query Tests', () => { name: 'Luke Skywalker', appearsIn: ['NEWHOPE', 'EMPIRE', 'JEDI'], friends: [ - { - name: 'Han Solo', - }, - { - name: 'Leia Organa', - }, - { - name: 'C-3PO', - }, - { - name: 'R2-D2', - }, + { name: 'Han Solo' }, + { name: 'Leia Organa' }, + { name: 'C-3PO' }, + { name: 'R2-D2' }, ], }, { name: 'Han Solo', appearsIn: ['NEWHOPE', 'EMPIRE', 'JEDI'], friends: [ - { - name: 'Luke Skywalker', - }, - { - name: 'Leia Organa', - }, - { - name: 'R2-D2', - }, + { name: 'Luke Skywalker' }, + { name: 'Leia Organa' }, + { name: 'R2-D2' }, ], }, { name: 'Leia Organa', appearsIn: ['NEWHOPE', 'EMPIRE', 'JEDI'], friends: [ - { - name: 'Luke Skywalker', - }, - { - name: 'Han Solo', - }, - { - name: 'C-3PO', - }, - { - name: 'R2-D2', - }, + { name: 'Luke Skywalker' }, + { name: 'Han Solo' }, + { name: 'C-3PO' }, + { name: 'R2-D2' }, ], }, ], @@ -170,71 +139,65 @@ describe('Star Wars Query Tests', () => { describe('Using IDs and query parameters to refetch objects', () => { it('Allows us to query for Luke Skywalker directly, using his ID', async () => { - const query = ` - query FetchLukeQuery { + const result = await executeQuery(` + { human(id: "1000") { name } } - `; - const result = await graphql(StarWarsSchema, query); + `); + expect(result).to.deep.equal({ data: { - human: { - name: 'Luke Skywalker', - }, + human: { name: 'Luke Skywalker' }, }, }); }); it('Allows us to create a generic query, then use it to fetch Luke Skywalker using his ID', async () => { const query = ` - query FetchSomeIDQuery($someId: String!) { + query ($someId: String!) { human(id: $someId) { name } } `; - const params = { someId: '1000' }; - const result = await graphql(StarWarsSchema, query, null, null, params); + const result = await executeQuery(query, { someId: '1000' }); + expect(result).to.deep.equal({ data: { - human: { - name: 'Luke Skywalker', - }, + human: { name: 'Luke Skywalker' }, }, }); }); it('Allows us to create a generic query, then use it to fetch Han Solo using his ID', async () => { const query = ` - query FetchSomeIDQuery($someId: String!) { + query ($someId: String!) { human(id: $someId) { name } } `; - const params = { someId: '1002' }; - const result = await graphql(StarWarsSchema, query, null, null, params); + const result = await executeQuery(query, { someId: '1002' }); + expect(result).to.deep.equal({ data: { - human: { - name: 'Han Solo', - }, + human: { name: 'Han Solo' }, }, }); }); it('Allows us to create a generic query, then pass an invalid ID to get null back', async () => { const query = ` - query humanQuery($id: String!) { + query ($id: String!) { human(id: $id) { name } } `; - const params = { id: 'not a valid id' }; - const result = await graphql(StarWarsSchema, query, null, null, params); + const result = await executeQuery(query, { id: 'not a valid id' }); + expect(result).to.deep.equal({ data: { human: null, @@ -245,26 +208,24 @@ describe('Star Wars Query Tests', () => { describe('Using aliases to change the key in the response', () => { it('Allows us to query for Luke, changing his key with an alias', async () => { - const query = ` - query FetchLukeAliased { + const result = await executeQuery(` + { luke: human(id: "1000") { name } } - `; - const result = await graphql(StarWarsSchema, query); + `); + expect(result).to.deep.equal({ data: { - luke: { - name: 'Luke Skywalker', - }, + luke: { name: 'Luke Skywalker' }, }, }); }); it('Allows us to query for both Luke and Leia, using two root fields and an alias', async () => { - const query = ` - query FetchLukeAndLeiaAliased { + const result = await executeQuery(` + { luke: human(id: "1000") { name } @@ -272,16 +233,12 @@ describe('Star Wars Query Tests', () => { name } } - `; - const result = await graphql(StarWarsSchema, query); + `); + expect(result).to.deep.equal({ data: { - luke: { - name: 'Luke Skywalker', - }, - leia: { - name: 'Leia Organa', - }, + luke: { name: 'Luke Skywalker' }, + leia: { name: 'Leia Organa' }, }, }); }); @@ -289,8 +246,8 @@ describe('Star Wars Query Tests', () => { describe('Uses fragments to express more complex queries', () => { it('Allows us to query using duplicated content', async () => { - const query = ` - query DuplicateFields { + const result = await executeQuery(` + { luke: human(id: "1000") { name homePlanet @@ -300,8 +257,8 @@ describe('Star Wars Query Tests', () => { homePlanet } } - `; - const result = await graphql(StarWarsSchema, query); + `); + expect(result).to.deep.equal({ data: { luke: { @@ -317,8 +274,8 @@ describe('Star Wars Query Tests', () => { }); it('Allows us to use a fragment to avoid duplicating content', async () => { - const query = ` - query UseFragment { + const result = await executeQuery(` + { luke: human(id: "1000") { ...HumanFragment } @@ -331,8 +288,8 @@ describe('Star Wars Query Tests', () => { name homePlanet } - `; - const result = await graphql(StarWarsSchema, query); + `); + expect(result).to.deep.equal({ data: { luke: { @@ -350,15 +307,15 @@ describe('Star Wars Query Tests', () => { describe('Using __typename to find the type of an object', () => { it('Allows us to verify that R2-D2 is a droid', async () => { - const query = ` - query CheckTypeOfR2 { + const result = await executeQuery(` + { hero { __typename name } } - `; - const result = await graphql(StarWarsSchema, query); + `); + expect(result).to.deep.equal({ data: { hero: { @@ -370,15 +327,15 @@ describe('Star Wars Query Tests', () => { }); it('Allows us to verify that Luke is a human', async () => { - const query = ` + const result = await executeQuery(` query CheckTypeOfLuke { hero(episode: EMPIRE) { __typename name } } - `; - const result = await graphql(StarWarsSchema, query); + `); + expect(result).to.deep.equal({ data: { hero: { @@ -392,15 +349,15 @@ describe('Star Wars Query Tests', () => { describe('Reporting errors raised in resolvers', () => { it('Correctly reports error on accessing secretBackstory', async () => { - const query = ` - query HeroNameQuery { + const result = await executeQuery(` + { hero { name secretBackstory } } - `; - const result = await graphql(StarWarsSchema, query); + `); + expect(result).to.deep.equal({ data: { hero: { @@ -419,8 +376,8 @@ describe('Star Wars Query Tests', () => { }); it('Correctly reports error on accessing secretBackstory in a list', async () => { - const query = ` - query HeroNameQuery { + const result = await executeQuery(` + { hero { name friends { @@ -429,8 +386,8 @@ describe('Star Wars Query Tests', () => { } } } - `; - const result = await graphql(StarWarsSchema, query); + `); + expect(result).to.deep.equal({ data: { hero: { @@ -472,15 +429,15 @@ describe('Star Wars Query Tests', () => { }); it('Correctly reports error on accessing through an alias', async () => { - const query = ` - query HeroNameQuery { + const result = await executeQuery(` + { mainHero: hero { name story: secretBackstory } } - `; - const result = await graphql(StarWarsSchema, query); + `); + expect(result).to.deep.equal({ data: { mainHero: { diff --git a/src/__tests__/starWarsSchema.js b/src/__tests__/starWarsSchema.js index 74e4ad3333..7110a632b4 100644 --- a/src/__tests__/starWarsSchema.js +++ b/src/__tests__/starWarsSchema.js @@ -7,17 +7,9 @@ * @flow strict */ -import { - GraphQLEnumType, - GraphQLInterfaceType, - GraphQLObjectType, - GraphQLList, - GraphQLNonNull, - GraphQLSchema, - GraphQLString, -} from '../type'; - -import { getFriends, getHero, getHuman, getDroid } from './starWarsData'; +import { buildSchema } from '../utilities/buildASTSchema'; +import { getCharacter, getHero, getHuman, getDroid } from './starWarsData'; +import type { CharacterData, HumanData, DroidData } from './starWarsData'; /** * This is designed to be an end-to-end test, demonstrating @@ -26,278 +18,166 @@ import { getFriends, getHero, getHuman, getDroid } from './starWarsData'; * We will create a GraphQL schema that describes the major * characters in the original Star Wars trilogy. * - * NOTE: This may contain spoilers for the original Star - * Wars trilogy. + * NOTE: This may contain spoilers for the original Star Wars trilogy. */ -/** - * Using our shorthand to describe type systems, the type system for our - * Star Wars example is: - * - * enum Episode { NEWHOPE, EMPIRE, JEDI } - * - * interface Character { - * id: String! - * name: String - * friends: [Character] - * appearsIn: [Episode] - * } - * - * type Human implements Character { - * id: String! - * name: String - * friends: [Character] - * appearsIn: [Episode] - * homePlanet: String - * } - * - * type Droid implements Character { - * id: String! - * name: String - * friends: [Character] - * appearsIn: [Episode] - * primaryFunction: String - * } - * - * type Query { - * hero(episode: Episode): Character - * human(id: String!): Human - * droid(id: String!): Droid - * } - * - * We begin by setting up our schema. - */ +export const StarWarsSchema = buildSchema(` + """One of the films in the Star Wars Trilogy""" + enum Episode { + """Released in 1977.""" + NEWHOPE, + """Released in 1980.""" + EMPIRE, + """Released in 1983.""" + JEDI + } -/** - * The original trilogy consists of three movies. - * - * This implements the following type system shorthand: - * enum Episode { NEWHOPE, EMPIRE, JEDI } - */ -const episodeEnum = new GraphQLEnumType({ - name: 'Episode', - description: 'One of the films in the Star Wars Trilogy', - values: { - NEWHOPE: { - value: 4, - description: 'Released in 1977.', - }, - EMPIRE: { - value: 5, - description: 'Released in 1980.', - }, - JEDI: { - value: 6, - description: 'Released in 1983.', - }, - }, -}); + """A character in the Star Wars Trilogy""" + interface Character { + """The id of the character.""" + id: String! + """The name of the character.""" + name: String + """The friends of the character, or an empty list if they have none.""" + friends: [Character] + """Which movies they appear in.""" + appearsIn: [Episode] + """All secrets about their past.""" + secretBackstory: String + } -/** - * Characters in the Star Wars trilogy are either humans or droids. - * - * This implements the following type system shorthand: - * interface Character { - * id: String! - * name: String - * friends: [Character] - * appearsIn: [Episode] - * secretBackstory: String - * } - */ -const characterInterface = new GraphQLInterfaceType({ - name: 'Character', - description: 'A character in the Star Wars Trilogy', - fields: () => ({ - id: { - type: GraphQLNonNull(GraphQLString), - description: 'The id of the character.', - }, - name: { - type: GraphQLString, - description: 'The name of the character.', - }, - friends: { - type: GraphQLList(characterInterface), - description: - 'The friends of the character, or an empty list if they ' + - 'have none.', - }, - appearsIn: { - type: GraphQLList(episodeEnum), - description: 'Which movies they appear in.', - }, - secretBackstory: { - type: GraphQLString, - description: 'All secrets about their past.', - }, - }), - resolveType(character) { - if (character.type === 'Human') { - return humanType; - } - if (character.type === 'Droid') { - return droidType; - } - }, -}); + """A humanoid creature in the Star Wars universe.""" + type Human implements Character { + """The id of the human.""" + id: String! + """The name of the human.""" + name: String + """The friends of the human, or an empty list if they have none.""" + friends: [Character] + """Which movies they appear in.""" + appearsIn: [Episode] + """The home planet of the human, or null if unknown.""" + homePlanet: String + """Where are they from and how they came to be who they are.""" + secretBackstory: String + } -/** - * We define our human type, which implements the character interface. - * - * This implements the following type system shorthand: - * type Human : Character { - * id: String! - * name: String - * friends: [Character] - * appearsIn: [Episode] - * secretBackstory: String - * } - */ -const humanType = new GraphQLObjectType({ - name: 'Human', - description: 'A humanoid creature in the Star Wars universe.', - fields: () => ({ - id: { - type: GraphQLNonNull(GraphQLString), - description: 'The id of the human.', - }, - name: { - type: GraphQLString, - description: 'The name of the human.', - }, - friends: { - type: GraphQLList(characterInterface), - description: - 'The friends of the human, or an empty list if they have none.', - resolve: human => getFriends(human), - }, - appearsIn: { - type: GraphQLList(episodeEnum), - description: 'Which movies they appear in.', - }, - homePlanet: { - type: GraphQLString, - description: 'The home planet of the human, or null if unknown.', - }, - secretBackstory: { - type: GraphQLString, - description: 'Where are they from and how they came to be who they are.', - resolve() { - throw new Error('secretBackstory is secret.'); - }, - }, - }), - interfaces: [characterInterface], -}); + """A mechanical creature in the Star Wars universe.""" + type Droid implements Character { + """The id of the droid.""" + id: String! + """The name of the droid.""" + name: String + """The friends of the droid, or an empty list if they have none.""" + friends: [Character] + """Which movies they appear in.""" + appearsIn: [Episode] + """Construction date and the name of the designer.""" + secretBackstory: String + """The primary function of the droid.""" + primaryFunction: String + } -/** - * The other type of character in Star Wars is a droid. - * - * This implements the following type system shorthand: - * type Droid : Character { - * id: String! - * name: String - * friends: [Character] - * appearsIn: [Episode] - * secretBackstory: String - * primaryFunction: String - * } - */ -const droidType = new GraphQLObjectType({ - name: 'Droid', - description: 'A mechanical creature in the Star Wars universe.', - fields: () => ({ - id: { - type: GraphQLNonNull(GraphQLString), - description: 'The id of the droid.', - }, - name: { - type: GraphQLString, - description: 'The name of the droid.', - }, - friends: { - type: GraphQLList(characterInterface), - description: - 'The friends of the droid, or an empty list if they have none.', - resolve: droid => getFriends(droid), - }, - appearsIn: { - type: GraphQLList(episodeEnum), - description: 'Which movies they appear in.', - }, - secretBackstory: { - type: GraphQLString, - description: 'Construction date and the name of the designer.', - resolve() { - throw new Error('secretBackstory is secret.'); - }, - }, - primaryFunction: { - type: GraphQLString, - description: 'The primary function of the droid.', - }, - }), - interfaces: [characterInterface], -}); + type Query { + hero( + """If omitted, returns the hero of the whole saga. If provided, returns the hero of that particular episode.""" + episode: Episode + ): Character + + human( + """id of the human""" + id: String! + ): Human + + droid( + """id of the droid""" + id: String! + ): Droid + } +`); + +// FIXME: +const episodeEnum = (StarWarsSchema.getType('Episode'): any); +(episodeEnum.getValue('NEWHOPE'): any).value = 4; +(episodeEnum.getValue('EMPIRE'): any).value = 5; +(episodeEnum.getValue('JEDI'): any).value = 6; + +class Character { + id: string; + name: string; + appearsIn: Array; + _friends: Array; + + constructor(data: CharacterData) { + this.id = data.id; + this.name = data.name; + this.appearsIn = data.appearsIn; + this._friends = data.friends; + } + + friends() { + // Notice that GraphQL accepts Arrays of Promises. + return this._friends.map(async id => { + const data = await getCharacter(id); + return makeCharacterObj(data); + }); + } + + secretBackstory() { + throw new Error('secretBackstory is secret.'); + } +} + +class Human extends Character { + __typename: string; + homePlanet: string; + + constructor(data: HumanData) { + super(data); + this.__typename = 'Human'; + this.homePlanet = data.homePlanet; + } +} + +class Droid extends Character { + __typename: string; + primaryFunction: string; + + constructor(data: DroidData) { + super(data); + this.__typename = 'Droid'; + this.primaryFunction = data.primaryFunction; + } +} + +function makeCharacterObj(data: CharacterData) { + switch (data.type) { + case 'Human': + return new Human(data); + case 'Droid': + return new Droid(data); + } +} /** * This is the type that will be the root of our query, and the * entry point into our schema. It gives us the ability to fetch * objects by their IDs, as well as to fetch the undisputed hero * of the Star Wars trilogy, R2-D2, directly. - * - * This implements the following type system shorthand: - * type Query { - * hero(episode: Episode): Character - * human(id: String!): Human - * droid(id: String!): Droid - * } - * */ -const queryType = new GraphQLObjectType({ - name: 'Query', - fields: () => ({ - hero: { - type: characterInterface, - args: { - episode: { - description: - 'If omitted, returns the hero of the whole saga. If ' + - 'provided, returns the hero of that particular episode.', - type: episodeEnum, - }, - }, - resolve: (root, { episode }) => getHero(episode), - }, - human: { - type: humanType, - args: { - id: { - description: 'id of the human', - type: GraphQLNonNull(GraphQLString), - }, - }, - resolve: (root, { id }) => getHuman(id), - }, - droid: { - type: droidType, - args: { - id: { - description: 'id of the droid', - type: GraphQLNonNull(GraphQLString), - }, - }, - resolve: (root, { id }) => getDroid(id), - }, - }), -}); +export class Query { + hero(args: { episode: number }) { + const data = getHero(args.episode); + return data ? makeCharacterObj(data) : null; + } -/** - * Finally, we construct our schema (whose starting query type is the query - * type we defined above) and export it. - */ -export const StarWarsSchema = new GraphQLSchema({ - query: queryType, - types: [humanType, droidType], -}); + human(args: { id: string }) { + const data = getHuman(args.id); + return data ? new Human(data) : null; + } + + droid(args: { id: string }) { + const data = getDroid(args.id); + return data ? new Droid(data) : null; + } +} From 9d37803f35374191785de6848a60c881dddf0265 Mon Sep 17 00:00:00 2001 From: Ivan Goncharov Date: Mon, 11 Jun 2018 16:04:11 +0300 Subject: [PATCH 2/3] Use getter function --- src/__tests__/starWarsSchema.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/__tests__/starWarsSchema.js b/src/__tests__/starWarsSchema.js index 7110a632b4..dd7dfbab53 100644 --- a/src/__tests__/starWarsSchema.js +++ b/src/__tests__/starWarsSchema.js @@ -129,25 +129,29 @@ class Character { } class Human extends Character { - __typename: string; homePlanet: string; constructor(data: HumanData) { super(data); - this.__typename = 'Human'; this.homePlanet = data.homePlanet; } + + get __typename(): string { + return 'Human'; + } } class Droid extends Character { - __typename: string; primaryFunction: string; constructor(data: DroidData) { super(data); - this.__typename = 'Droid'; this.primaryFunction = data.primaryFunction; } + + get __typename(): string { + return 'Droid'; + } } function makeCharacterObj(data: CharacterData) { From eef0878d851f7b8a4392b031550a1080497c018c Mon Sep 17 00:00:00 2001 From: Ivan Goncharov Date: Mon, 11 Jun 2018 16:22:29 +0300 Subject: [PATCH 3/3] Add hack to path enum with values --- src/__tests__/starWarsSchema.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/__tests__/starWarsSchema.js b/src/__tests__/starWarsSchema.js index dd7dfbab53..12358462e2 100644 --- a/src/__tests__/starWarsSchema.js +++ b/src/__tests__/starWarsSchema.js @@ -96,11 +96,14 @@ export const StarWarsSchema = buildSchema(` } `); -// FIXME: +// FIXME: Patch enum defined in SDL, should be possible to do without hacks :( const episodeEnum = (StarWarsSchema.getType('Episode'): any); -(episodeEnum.getValue('NEWHOPE'): any).value = 4; -(episodeEnum.getValue('EMPIRE'): any).value = 5; -(episodeEnum.getValue('JEDI'): any).value = 6; +episodeEnum.getValue('NEWHOPE').value = 4; +episodeEnum.getValue('EMPIRE').value = 5; +episodeEnum.getValue('JEDI').value = 6; +for (const enumValue of episodeEnum.getValues()) { + episodeEnum._valueLookup.set(enumValue.value, enumValue); +} class Character { id: string;