Type checking preventing missing fields from being projected as null

According to the docs:

If a requested field doesn’t exist in the projected object, the returned field value is set to null.

So why is the type system inferring that a projected field doesn’t exist and throwing an error? I’m trying to use projection to add in any missing fields

We could probably clarify the docs. Can you link to the specific page that is from?

At this time, where we haven’t released schema enforcement, all documents are essentially of type { *: Any }. So you can project any fields you want because any and all fields are nullable. But you cannot select for a field that is known to not exist.

To say it another way, a nullable field will be null if it is missing from an object, but the field has to exist in the type for you to request it in the first place.

When you assign an object literal to a variable, it’s type is literally the object you provided. Check out the type info from my query here:

In my case, I can project for the fields I defined, but not for a new field

Declare types for your variables

You can declare a type for your variable, either by being explicit about the fields, or setting the whole object to Any or { *: Any }

At the top of this page:

1 Like

This seems counterintuitive to me. When projecting, you are creating a new type. After all, you can redefine fieldnames and even add in completely new fields from outside the object. Why then should you be limited by the original type when performing projection.

This is consistent with any other typed language. Even Typescript.

Consider that a projection is desugared like this:

const x = {
  nonNullable: 42,
  nullable: null,
}

// The original projection
x {
  nonNullable,
  nullable,
  missing
}
// desugar the selected fields
x {
  nonNullable: .nonNullable,
  nullable: .nullable,
  missing: .missing
}
// desugar the whole projection
{
  nonNullable: x.nonNullable,
  nullable: x.nonNullable,
  missing: x.missing // This is a clear type error, because x has no field called "missing"
}

In Typescript, the type of an object literal is the given object structure, similar to FQL. Trying to do something results in a type error

More workarounds

The issue is the implicit x.missing that is being read. If you know which fields are missing, then you can explicitly set them to null

x {
  nonNullable,
  nullable,
  missing: null // now okay because I am not trying to read `x.missing`
}
1 Like