Skip to content

Static typing lost when a conditional uses a string template and more than one condition is present #398

@narkowicz

Description

@narkowicz

Is there an existing issue for this?

  • I have searched the existing issues

Code of Conduct

  • I agree to follow this project's Code of Conduct

Code Sandbox link

No response

Bug report

Have noticed that typing of returned objects is lost if string templating is used in the filter of a conditional statement.

Reporting as a bug since the conditional strings are not strongly typed and the filter used shouldn't impact the eventual types (since it resolves to either true or false, regardless of whether it includes template variables).

`v1.7.1`

Consider these examples:


1. A single template string works as expected:

/**
 * @returns ({} | {
 *   title: string | null;
 * })[]
 */
const singleTemplateString = (variable: string) => sanityQuery(q.star
  .filterByType('page')
  .project(sub => (sub.conditional({
    [`[some condition] ${variable}`]: { title: true },
  })))
);


2. A variable template string with second static condition casts types to `undefined` (note that the return type is _not_ a union):

/**
 * @returns ({} | {
 *   slug?: undefined;
 *   title?: undefined;
 * })[]
 */
export const withVariableTemplateString = (variable: string) => sanityQuery(q.star
  .filterByType('page')
  .project(sub => (sub.conditional({
    [`[some condition] ${variable}`]: { title: true },
    [`[another condition]`]: { slug: true },
  })))
);


3. Casting to a string literal no longer resolves to `undefined`


/**
 * @returns ({} | {
 *   slug: SanityTypes.Slug | null;
 * } | {
 *   title: string | null;
 * })[]
 */
export const withConstantTemplateString = (variable: string) => sanityQuery(q.star
  .filterByType('page')
  .project(sub => (sub.conditional({
    [`[some condition] ${variable}` as '']: { title: true },
    [`[another condition]`]: { slug: true },
  })))
);


Note: the return type is a union of each condition, but in practice multiple
conditions can be true at once—and the returned data in real usage reflects this.
I'm using `type-fest`'s `UnionToIntersection` to cast the union to an intersection
to work-around this-but probably warrants a separate issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions