facebook/relay

Type safety not catching null/undefined arrays in generated types

Opened this issue · 0 comments

Type safety not catching null/undefined arrays in generated types

Description

When using react-relay's generated types, TypeScript is not catching potential null/undefined arrays in the GraphQL response. This leads to runtime errors that should be caught at compile time.

Reproduction

Given this GraphQL fragment:

graphql fragment SiteLoadGraphFragment on ChargingSite { chargers { connectors { filteredChargingSchedule: chargingSchedule( where: { startTime: $dateFilter, endTime: $dateFilter } ) { id startTime endTime timeTarget energyTarget loads { start stop load } } } } }

And this component code:

function SiteLoadGraph({ data, timeWindow }: SiteLoadGraphProps) {
  const siteData = useFragment(SiteLoadGraphData, data);
  const getLoadOverTime = (chargers: Charger, timeWindow: StartEndTimes) => {
    mutableChargers.forEach((charger) => {
      charger.connectors.forEach((connector) => {
      // This line throws at runtime but TypeScript doesn't catch it
      connector.filteredChargingSchedule.forEach((schedule) => {
      // ...
      });
    });
  });
  };
  // ...
}

Expected Behavior

TypeScript should warn about potential null/undefined values when trying to call .forEach() on filteredChargingSchedule without first checking if it exists and is an array.

Actual Behavior

No TypeScript errors are shown, but at runtime we get:

Uncaught TypeError: Cannot read properties of undefined (reading 'forEach')

Questions

  1. Why aren't the generated types preserving nullability information from the GraphQL schema?
  2. Should we be handling this differently in our code?
  3. Is this a configuration issue with the GraphQL codegen?

Environment

  • react-relay version: 18.1.0
  • TypeScript version: 5.3.3
  • relay-compiler version:18.1.0

Additional Context

This is particularly important for type safety as these kinds of runtime errors should be caught during development. The current behavior defeats the purpose of using TypeScript with GraphQL's type generation.