Typescript: retrieve the data type of the initial property within a specified type

After running a GraphQL query, I receive a nested object where the query name serves as the first-level key and the actual data is located on the second level:

{
    getProduct: {
        id: "1",
        name: "test",
    }
}

Within my query function, I have set it up to automatically extract the first key of the object and return the value of getProduct. However, I am looking for a way to determine the type of the first key as the return value of the query function.

type QueryReturn = FirstElement<GetProductQuery>; // should be { id: string; name: string }

All of the solutions I've come across online focus on inferring the Head or Tail of an Array or Function.

Answer №1

I may be fashionably late to the gathering, but I couldn't help but notice your utilization of graphql-codegen. I encountered a similar issue which I resolved using:

type DataType = {
  __typename?: string;
};

type FilteredQuery<T> = {
  [P in keyof T as T[P] extends DataType ? P : never]: T[P];
};

type QueryData<T> = FilteredQuery<T>[keyof FilteredQuery<T>];

Check out the TypeScript playground example.

Answer №2

It's a bit delayed response. If you can ensure that there is always a single key in the outermost type, you can achieve it by using the keyof operator and indexed access type.

This approach may act unpredictably if there are no keys or multiple keys in the outermost type, so it is crucial to have exactly one key in all scenarios.

For example:

type Unwrap<T> = T[keyof T];

type QueryReturn = Unwrap<GetProductQuery>;

Playground Link

Answer №3

So if I understand correctly, you're just trying to access the product type without using the getProduct alias in between?

I have a feeling that this additional layer is present because of query aliasing. However, there isn't a first key in an object. To navigate through, you would need to specify the key. One way to simplify this process is by automatically generating types using a tool such as graphql-autogen.

Answer №4

When considering your specific needs, it is possible to alias queries to standardize their results.

Consider the following code snippet:

export const MyComponent_FooEntity_QueryDocument = graphql(`
  query MyComponent_FooEntity_Query($id: Id!) {
    findMyFoo(id: $id) {
      # Fields
    }
  }
`)

export const MyComponent_BarEntity_QueryDocument = graphql(`
  query MyComponent_BarEntity_Query($id: Id!) {
    findMyBar(id: $id) {
      # Fields
    }
  }
`)

You can modify it as follows:

export const MyComponent_FooEntity_QueryDocument = graphql(`
  query MyComponent_FooEntity_Query($id: Id!) {
    queryResult: findMyFoo(id: $id) {
      # Fields
    }
  }
`)

export const MyComponent_BarEntity_QueryDocument = graphql(`
  query MyComponent_BarEntity_Query($id: Id!) {
    queryResult: findMyBar(id: $id) {
      # Fields
    }
  }
`)

This allows you to access your data type in a standardized manner:

  import type { ResultOf } from '@graphql-typed-document-node/core';

  type QueryResult = ResultOf<
    typeof MyComponent_BarEntity_QueryDocument
  >['queryResult']

Alternatively, you can create a utility function:

export const getQueryResult = <R,>(query: { readonly queryResult: R }): R => query.queryResult

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the appropriate Typescript return type to use for a $http request that only returns a successful response with no content?

I recently developed a Typescript service: class SettingsService implements ISettingsService { public info = {}; public backupInfo = {}; public userConfig = {}; public isLoaded = false; constructor( private $http: ng.IHttpSer ...

The Element type does no feature a Typescript property

Despite my attempts to include a declaration file and various other solutions, I'm still struggling with this issue: The goal is to define the visible property as a function on the HTML Element object. However, the linter keeps flagging visible with ...

How can Observable data be transferred to PDF (pdfMake) in Ionic with Angular?

I am currently utilizing pdfMake to create PDFs from observable data, but I am encountering an issue where the PDF either appears empty or displays [object Object]. Below is the snippet of my code: downloadPDF() { pdfMake.vfs = pdfFonts.pdfMake.vfs; ...

Unable to bring in an exported class from a TypeScript file

I have a TypeScript file named foo.ts that contains an exported class called "Foo" export default class Foo{ } I am attempting to import this class into another file within the same directory import {Foo} from './foo'; However, I am encounter ...

Looking to create universal React component wrappers?

I am working with a set of functional components that share a common set of properties, for example: const A = ({ x, y, z }) = {...} const B = ({ x, y, z }) = {...} For these components, I have predefined configurations: const styles { A: { ty ...

A guide to effectively injecting a service into a guard

I've encountered a challenge while working on an API using nestjs, specifically with service injection in a guard. The error message I'm facing is: Error: Nest can't resolve dependencies of the AuthorizerGuard (?). Please make sure that the ...

A unique Angular service that is private and initialized with a specific parameter

My Angular Service (myService) is injected into multiple components and services through their constructors. I want each usage of myService to have its own instance to ensure no data is shared among them. Additionally, I would like myService to be initia ...

Using a class constructor as an argument for a function that requires a specific function type

Let's consider a scenario where we have a function defined as (fooMaker: (_: string) => Foo): void, in which Foo represents a class. Is there a way to directly pass the constructor of Foo to this function without needing to encase it like so: (s: s ...

fakeAsync failing to synchronize with async task completion

Scenario In my testing process, I am evaluating a component that utilizes an observable-based service to retrieve and display data for internationalization purposes. The i18n service is custom-made to cater to specific requirements. While the component ...

Encountering a problem when attempting to save time without a timezone in PostgreSQL

I'm experiencing a problem inserting a time value into the startTime field of my entity in PostgreSQL. Here is the relevant code snippet: @Property({ type: 'time' }) startTime!: Date; Within my service function: await this.persistAndFlush(c ...

Once the table is created in TypeORM, make sure to insert essential master data such as types and statuses

Hey there, I have a question regarding NestJS and typeORM. My issue is with inserting default values into tables after creating them. For example, I have a priority table where I need to insert High/Medium/Low values. Despite trying everything in the typeo ...

Looking to adjust the height of a foreignObject element within an SVG?

Looking to dynamically change the height of a foreignObject within an SVG, while also needing HTML elements inside it (working with ngx-graph). <foreignObject x="1" y="1" width="335" [height]="foreignObjHeight(node.Dat ...

Steps for linking HTTP requests in Angular 2 depending on the type of response

My attempt to create an api call from a remote server and then, if an error occurs, make another request from my local server is not working as expected. I am encountering errors and need help to determine if my approach is feasible. Here is the code snip ...

Running a function before triggering a refresh in Angular 2/4

When a user clicks or presses the F5 button on an HTML page, the page refreshes. However, before the refresh occurs, I want to execute a function or display a simple alert. The user can trigger a refresh by clicking the refresh button, pressing F5, or usi ...

The type 'ReadableStream<any>' cannot be assigned to the parameter type 'ReadableStream'

Is there a way to convert a Blob into a Readable format? import {Readable} from 'stream'; const data: Blob = new Blob( ); const myReadable: Readable = (new Readable()).wrap(data.stream()); myReadable.pipe(ext); Encountering an error: ERROR in s ...

Unable to perform a default import in Angular 9 version

I made adjustments to tsconfig.json by adding the following properties: "esModuleInterop": true, "allowSyntheticDefaultImports": true, This was done in order to successfully import an npm package using import * as ms from "ms"; Despite these changes, I ...

What is the reason that {a: never} is not the same as never?

Is there a reason the code {a: never} cannot be simplified to just never? I believe this change would resolve the issues mentioned below. type A = {tag: 'A', value: number} type B = {tag: 'B', value: boolean} type N = {tag: never, valu ...

Bring in personalized tag to TypeScript

I am working on a TypeScript file to generate an HTML page. Within this code, I want to import the module "model-viewer" and incorporate it into my project. import * as fs from "fs"; import prettier from "prettier"; import React from "react"; import ReactD ...

Error: Query is not valid

I'm encountering an error when trying to run this query, and I'm not sure why it's returning a bad request. My goal is to fetch a specific user from the database using the accountId. Can someone assist me with this issue? Below is the funct ...

Testing a default export class method with Jest in Typescript

Scenario: I have a custom hook that relies on @react-native-firebase/dynamic-links for testing. We are using @testing-library and its utilities for react-native to test hooks (@testing-library/react-hooks). Below is the simplified example of the hook I w ...