Skip to content

Commit

Permalink
fix: Fix readFragment() not deriving complex return types (#15)
Browse files Browse the repository at this point in the history
  • Loading branch information
kitten committed Jan 17, 2024
1 parent 5ec067e commit 018823f
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 8 deletions.
5 changes: 5 additions & 0 deletions .changeset/neat-numbers-shake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'gql.tada': patch
---

Fix `readFragment()` not inferring the types of complex fragments, i.e. fragments that derive with a union type.
73 changes: 72 additions & 1 deletion src/__tests__/api.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { describe, it, expectTypeOf } from 'vitest';
import type { mirrorFragmentTypeRec } from '../api';

import type { simpleSchema } from './fixtures/simpleSchema';
import type { parseDocument } from '../parser';
import type { ResultOf, FragmentOf, mirrorFragmentTypeRec, getDocumentNode } from '../api';
import { readFragment } from '../api';

type schema = simpleSchema;
type value = { __value: true };
type data = { __data: true };

Expand All @@ -24,4 +29,70 @@ describe('mirrorFragmentTypeRec', () => {
>();
expectTypeOf<mirrorFragmentTypeRec<readonly value[], data>>().toEqualTypeOf<readonly data[]>();
});

it('mirrors complex types', () => {
type complex = { a: true } | { b: true };
type actual = mirrorFragmentTypeRec<value, complex>;
expectTypeOf<actual>().toEqualTypeOf<complex>();
});
});

describe('readFragment', () => {
it('unmasks regular fragments', () => {
type fragment = parseDocument<`
fragment Fields on Todo {
id
}
`>;

type document = getDocumentNode<fragment, schema>;
const result = readFragment({} as document, {} as FragmentOf<document>);
expectTypeOf<typeof result>().toEqualTypeOf<ResultOf<document>>();
});

it('unmasks fragments with optional spreads', () => {
type fragment = parseDocument<`
fragment Fields on Todo {
... @defer {
id
}
}
`>;

type document = getDocumentNode<fragment, schema>;
const result = readFragment({} as document, {} as FragmentOf<document>);
expectTypeOf<typeof result>().toEqualTypeOf<ResultOf<document>>();
});

it('unmasks fragments of interfaces', () => {
type fragment = parseDocument<`
fragment Fields on ITodo {
id
... on BigTodo {
wallOfText
}
... on SmallTodo {
maxLength
}
}
`>;

type document = getDocumentNode<fragment, schema>;
const result = readFragment({} as document, {} as FragmentOf<document>);
expectTypeOf<typeof result>().toEqualTypeOf<ResultOf<document>>();
});

it('unmasks fragments of interfaces with optional spreads', () => {
type fragment = parseDocument<`
fragment Fields on ITodo {
... on ITodo @defer {
id
}
}
`>;

type document = getDocumentNode<fragment, schema>;
const result = readFragment({} as document, {} as FragmentOf<document>);
expectTypeOf<typeof result>().toEqualTypeOf<ResultOf<document>>();
});
});
10 changes: 3 additions & 7 deletions src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ function parse<const In extends stringLiteral<In>>(input: In): parseDocument<In>
return _parse(input) as any;
}

type getDocumentNode<
export type getDocumentNode<
Document extends DocumentNodeLike,
Introspection extends IntrospectionLikeType,
Fragments extends { [name: string]: any } = {},
Expand Down Expand Up @@ -347,13 +347,9 @@ type fragmentOfTypeRec<Document extends DocumentDefDecorationLike> =
* @see {@link readFragment} for how to read from fragment masks.
*/
function readFragment<
const Document extends DocumentDefDecorationLike,
const Document extends DocumentDefDecorationLike & DocumentDecoration<any, any>,
const Fragment extends fragmentOfTypeRec<Document>,
const Data,
>(
_document: DocumentDecoration<Data, any> & Document,
fragment: Fragment
): fragmentOfTypeRec<Document> extends Fragment ? unknown : mirrorFragmentTypeRec<Fragment, Data> {
>(_document: Document, fragment: Fragment): mirrorFragmentTypeRec<Fragment, ResultOf<Document>> {
return fragment as any;
}

Expand Down

0 comments on commit 018823f

Please sign in to comment.