@@ -9,7 +9,7 @@ export interface Character {
99 appearsIn : ReadonlyArray < number > ;
1010}
1111
12- export interface Human {
12+ export interface Human extends Character {
1313 type : 'Human' ;
1414 id : string ;
1515 name : string ;
@@ -18,7 +18,7 @@ export interface Human {
1818 homePlanet ?: string ;
1919}
2020
21- export interface Droid {
21+ export interface Droid extends Character {
2222 type : 'Droid' ;
2323 id : string ;
2424 name : string ;
@@ -35,93 +35,110 @@ export interface Droid {
3535 * JSON objects in a more complex demo.
3636 */
3737
38- const luke : Human = {
38+ const luke = {
3939 type : 'Human' ,
4040 id : '1000' ,
4141 name : 'Luke Skywalker' ,
4242 friends : [ '1002' , '1003' , '2000' , '2001' ] ,
4343 appearsIn : [ 4 , 5 , 6 ] ,
4444 homePlanet : 'Tatooine' ,
45- } ;
45+ } as const satisfies Human ;
4646
47- const vader : Human = {
47+ const vader = {
4848 type : 'Human' ,
4949 id : '1001' ,
5050 name : 'Darth Vader' ,
5151 friends : [ '1004' ] ,
5252 appearsIn : [ 4 , 5 , 6 ] ,
5353 homePlanet : 'Tatooine' ,
54- } ;
54+ } as const satisfies Human ;
5555
56- const han : Human = {
56+ const han = {
5757 type : 'Human' ,
5858 id : '1002' ,
5959 name : 'Han Solo' ,
6060 friends : [ '1000' , '1003' , '2001' ] ,
6161 appearsIn : [ 4 , 5 , 6 ] ,
62- } ;
62+ } as const satisfies Human ;
6363
64- const leia : Human = {
64+ const leia = {
6565 type : 'Human' ,
6666 id : '1003' ,
6767 name : 'Leia Organa' ,
6868 friends : [ '1000' , '1002' , '2000' , '2001' ] ,
6969 appearsIn : [ 4 , 5 , 6 ] ,
7070 homePlanet : 'Alderaan' ,
71- } ;
71+ } as const satisfies Human ;
7272
73- const tarkin : Human = {
73+ const tarkin = {
7474 type : 'Human' ,
7575 id : '1004' ,
7676 name : 'Wilhuff Tarkin' ,
7777 friends : [ '1001' ] ,
7878 appearsIn : [ 4 ] ,
79- } ;
79+ } as const satisfies Human ;
8080
81- const humanData : { [ id : string ] : Human } = {
81+ const humanData = {
8282 [ luke . id ] : luke ,
8383 [ vader . id ] : vader ,
8484 [ han . id ] : han ,
8585 [ leia . id ] : leia ,
8686 [ tarkin . id ] : tarkin ,
87- } ;
87+ } as const satisfies { [ id : string ] : Human } ;
8888
89- const threepio : Droid = {
89+ type HumanData = typeof humanData ;
90+ type AnyHumanId = keyof HumanData ;
91+ type AnyHuman = HumanData [ AnyHumanId ] ;
92+
93+ const threepio = {
9094 type : 'Droid' ,
9195 id : '2000' ,
9296 name : 'C-3PO' ,
9397 friends : [ '1000' , '1002' , '1003' , '2001' ] ,
9498 appearsIn : [ 4 , 5 , 6 ] ,
9599 primaryFunction : 'Protocol' ,
96- } ;
100+ } as const satisfies Droid ;
97101
98- const artoo : Droid = {
102+ const artoo = {
99103 type : 'Droid' ,
100104 id : '2001' ,
101105 name : 'R2-D2' ,
102106 friends : [ '1000' , '1002' , '1003' ] ,
103107 appearsIn : [ 4 , 5 , 6 ] ,
104108 primaryFunction : 'Astromech' ,
105- } ;
109+ } as const satisfies Droid ;
106110
107- const droidData : { [ id : string ] : Droid } = {
111+ const droidData = {
108112 [ threepio . id ] : threepio ,
109113 [ artoo . id ] : artoo ,
110- } ;
114+ } as const satisfies { [ id : string ] : Droid } ;
115+
116+ type DroidData = typeof droidData ;
117+ type AnyDroidId = keyof DroidData ;
118+ type AnyDroid = DroidData [ AnyDroidId ] ;
119+
120+ type AnyCharacter = AnyHuman | AnyDroid ;
121+ type AnyCharacterId = AnyCharacter [ 'id' ] ;
122+
123+ const isHumanId = ( id : AnyCharacterId ) : id is AnyHumanId =>
124+ Object . hasOwn ( humanData , id ) ;
111125
112126/**
113127 * Helper function to get a character by ID.
114128 */
115- function getCharacter ( id : string ) : Promise < Character | null > {
116- // Returning a promise just to illustrate that GraphQL.js supports it.
117- return Promise . resolve ( humanData [ id ] ?? droidData [ id ] ) ;
129+ function getCharacter ( id : AnyCharacterId ) : Promise < AnyCharacter > {
130+ if ( isHumanId ( id ) ) {
131+ return Promise . resolve ( humanData [ id ] ) ;
132+ }
133+
134+ return Promise . resolve ( droidData [ id ] ) ;
118135}
119136
120137/**
121138 * Allows us to query for a character's friends.
122139 */
123- export function getFriends (
124- character : Character ,
140+ export function getFriends < T extends AnyCharacter > (
141+ character : T ,
125142) : Array < Promise < Character | null > > {
126143 // Notice that GraphQL accepts Arrays of Promises.
127144 return character . friends . map ( ( id ) => getCharacter ( id ) ) ;
@@ -142,13 +159,13 @@ export function getHero(episode: number): Character {
142159/**
143160 * Allows us to query for the human with the given id.
144161 */
145- export function getHuman ( id : string ) : Human | null {
162+ export function getHuman ( id : AnyHumanId ) : AnyHuman {
146163 return humanData [ id ] ;
147164}
148165
149166/**
150167 * Allows us to query for the droid with the given id.
151168 */
152- export function getDroid ( id : string ) : Droid | null {
169+ export function getDroid ( id : AnyDroidId ) : Droid {
153170 return droidData [ id ] ;
154171}
0 commit comments