facebook / facebook/relay

[relay-compiler] Incorrect typing of `__typename` in types generated by `@raw_query_response`

Open
#4,442 3 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
19k
Forks
1.9k
PR merge metrics
No merged PRs in 30d

Description

## What did you do?

I am using [msw](https://github.com/mswjs/msw) to mock the GraphQL request and return a dummy response. And to generate the correct dummy response, I am using `@raw_query_response` to generate the query response type.

```tsx
import {graphql} from "react-relay";
import {TestQuery$rawResponse} from './__generated__/TestQuery.graphql';

graphql`
query TestQuery($id: ID!) @raw_response_type {
node(id: $id) {
...TestQuery_node
}
}
`

graphql`
fragment TestQuery_node on Node {
id
__typename
... on Book {
title
}
... on Author {
name
}
}
`

// ok
const mockResponse1: TestQuery$rawResponse = {
node: {
__typename: 'Book',
__isNode: 'Book',
id: 'Book-1',
title: 'Yuyushiki',
},
}

// ok
const mockResponse2: TestQuery$rawResponse = {
node: {
__typename: 'Author',
__isNode: 'Author',
id: 'Author-1',
name: 'Bob',
},
}
```

## What actually happened?

If a field of `Book` type is missing, no type error occurs.

```ts
// This passes the type check.
const mockResponse3: TestQuery$rawResponse = {
node: {
__typename: 'Book',
__isNode: 'Book',
id: 'Book-1',
// title: 'Yuyushiki', // missing
},
}
```

## What did you expect to happen?
For `Book` type, `title` field should be required. Therefore, a type error should be reported.

## Additional Context
The problem seems to be caused by a loose type of `@raw_response_type` generated by relay-compiler. The actual response type generated by relay-compiler is shown below.

```ts
// src/__generated__/TestQuery.graphql.ts
// ...
export type TestQuery$rawResponse = {
readonly node: {
readonly __typename: "Author";
readonly __isNode: "Author";
readonly id: string;
readonly name: string;
} | {
readonly __typename: "Book";
readonly __isNode: "Book";
readonly id: string;
readonly title: string;
} | {
readonly __typename: string;
readonly __isNode: string;
readonly id: string;
};
};
// ...
```

The last `{ readonly __typename: string; readonly __isNode: string; readonly id: string; }` is important. The type of `mockResponse3` matches this, so it passes the type check.

I think the relay-compiler should generate a response type that is strictly `__typename` typed, as follows:

```ts
// src/__generated__/TestQuery.graphql.ts
// ...

// The union types that accept the names of all GraphQL types
type TypeName = "Author" | "Book" | "Image";

export type TestQuery$rawResponse = {
readonly node: {
readonly __typename: "Author";
readonly __isNode: "Author";
readonly id: string;
readonly name: string;
} | {
readonly __typename: "Book";
readonly __isNode: "Book";
readonly id: string;
readonly title: string;
} | {
readonly __typename: Exclude;
readonly __isNode: Exclude;
readonly id: string;
};
};
// ...
```

## Link to Minimal Reproducible Example

- https://github.com/mizdra/relay-compiler-issue-repro

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.