Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: update variable type variance to bivariant #161

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

StationSoen
Copy link

@StationSoen StationSoen commented Jan 5, 2024

Summary

I've updated the implementation of the __apiType method to shorthand method definition. This modification enables bivariance in the variable type.

Details

Let's consider a function that takes a specific TypedDocumentNode with certain requirements. Assume this function, queryAnimal, receives a Graphql query with AnimalQueryResult as the return type and AnimalQueryVariable as the argument type.

Suppose dogDocumentNode has a narrower scope than AnimalQueryResult for the Return Type ({ name: string; id: string; age: number }) and a narrower scope than AnimalQueryVariable for the Variable Type ({ id: string }). As a result, it should be usable as an argument for queryAnimal. However, due to the Variable Type of TypedDocumentNode being a function argument, TypeScript conducts type checking contravariantly for the VariableType, making it ineligible as an argument.

To create a bivariant function argument in TypeScript, the method needs to be defined as a Shorthand Definition.

type ResultOf<T> = T extends TypedDocumentNode<infer R, any> ? R : never;
type VariablesOf<T> = T extends TypedDocumentNode<any, infer V> ? V : never;

// type TypedDocumentNode<R, V> = { __apiType?: (variables: V) => R }; // AS-IS
type TypedDocumentNode<R, V> = { __apiType?(variables: V): R }; // TO-BE

type AnimalQueryResult = Record<
  string,
  { name: string; id: string; age: number; [key: string]: any }
>;
type AnimalQueryVariable = Record<string, any>;

function queryAnimal<
  DN extends TypedDocumentNode<R, V>,
  R extends AnimalQueryResult,
  V extends AnimalQueryVariable
>(query: DN, variable: VariablesOf<DN>): ResultOf<DN> {
  return "" as any;
}

const dogDocumentNode = "" as TypedDocumentNode<
  { dogQuery: { name: string; id: string; age: number } },
  { id: string }
>;
const dog = queryAnimal(dogDocumentNode, { id: "5172" });

const catDocumentNode = "" as TypedDocumentNode<
  { catQuery: { name: string; id: string } },
  { id: string }
>;
const cat = queryAnimal(catDocumentNode, { id: "5713" });

References

TypeScript FAQ: Why are function parameters bivariant?
Typescript Repo: Strict function types #18654

Copy link

changeset-bot bot commented Jan 5, 2024

⚠️ No Changeset found

Latest commit: ab9e8c3

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@dotansimha dotansimha requested review from n1ru4l and saihaj January 7, 2024 09:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant