Tips for creating parameterized keys for a specific type in Typescript

I've encountered a challenge while transitioning my react-native project from Flow to TypeScript. The stumbling block is recreating this specific type from Flow:

declare type ApolloData<T, nodeName: string = 'node'> = {
  [nodeName]: ?T,
  viewer?: ?Viewer,
  placeSearch?: ?PlaceConnection,
  contactIqLookup?: ?ContactIq,
};

This structure allowed me to type my GraphQL data like this:

const data: ApolloData<Space> = fetchData();
const space: Space = data.node;
// OR
const data: ApolloData<Space, 'space'> = fetchData();
const space: Space = data.space;

In my attempt to replicate this in TypeScript, I initially wrote this:

type ApolloData<T, nodeName extends string = 'node'> = {
  [node: nodeName]: T | null;
  viewer?: Viewer | null;
  placeSearch?: PlaceConnection | null;
  contactIqLookup?: ContactIq | null;
}

Unfortunately, this led to an error:

TS1023: An index signature parameter type must be 'string' or 'number'.

Further research introduced me to the Record type, which seemed promising. My revised attempt looked like this:

type ApolloData<T, nodeName extends string = 'node'> = 
    Record<nodeName, T | null> &
    {
      viewer?: Viewer | null;
      placeSearch?: PlaceConnection | null;
      contactIqLookup?: ContactIq | null;
    }

However, a drawback of this approach is that the other properties are typed as viewer: Viewer | null | T instead of just Viewer | null due to the Record type handling all object properties.

Is there a way in TypeScript to accommodate a generic parameterized key and value while also incorporating other fields?

Answer №1

What if we break up the Record definition for static attributes and then combine them later?

type ContactIq = { _type: "ContactIq" };
type PlaceConnection = { _type: "PlaceConnection" };
type Viewer = { _type: "Viewer" };

type DataOnly<T, nodeName extends string> = Record<nodeName, T | null>;

interface OtherAttributes {
  viewer?: Viewer | null;
  placeSearch?: PlaceConnection | null;
  contactIqLookup?: ContactIq | null;
}

type ApolloData<T, nodeName extends string = 'node'> = OtherAttributes & DataOnly<T, nodeName>;

const data1: ApolloData<string> = {
  node: "test",
  viewer: { _type: "Viewer" },
  contactIqLookup: { _type: "ContactIq" },
  placeSearch: { _type: "PlaceConnection" }
}

const data2: ApolloData<string, "abc"> = {
  abc: "test",
  viewer: { _type: "Viewer" },
  contactIqLookup: { _type: "ContactIq" },
  placeSearch: { _type: "PlaceConnection" }
}

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 are the steps to resolving an issue in a Jest unit test?

In my ReactJs/Typescript project, I encountered an issue while running a unit test that involves a reference to a module called nock.js and using jest. Initially, the import statement was causing an error in the .cleanAll statement: import nock from &apos ...

Creating a nested observable in Angular2: A step-by-step guide

Currently, I am exploring a new approach in my Angular2 service that involves using observables. The data source for this service will initially be local storage and later updated when an HTTP call to a database returns. To achieve this dynamic updating of ...

What steps can be taken to initiate Nx Release on the apps/* when modifications are made to the connected libs/* modules?

Trying out the nx release command but struggling to get it to release an app when there are changes to a dependent module. Examining the graph below, you can see that I have 3 apps, with 2 depending on the shared-ui module. https://i.sstatic.net/QYDBlRnZ.p ...

Angular 6 offers a dynamic auto complete feature that enhances user

My Angular app has auto-complete functionality enabled. I am using ngFor to iterate over an array of objects and passing the index of the object array to a function for some operations. Below is the code snippet I have tried: template.html <mat-form ...

Tips on searching for an entry in a database with TypeScript union types when the type is either a string or an array of strings

When calling the sendEmail method, emails can be sent to either a single user or multiple users (with the variable type string | string[]). I'm trying to find a more efficient and cleaner way to distinguish between the two in order to search for them ...

What is the process for integrating TypeScript compiling into a JavaScript application?

My project includes a build.js file that is responsible for building the project. It has two main objectives: Compile .ts files and store them in a new directory. Create an asar archive containing the compiled files. Since typescript (or tsc) is availabl ...

Error in JSON format detected by Cloudinary in the live environment

For my upcoming project in Next.js, I have integrated a Cloudinary function to handle file uploads. Here is the code snippet: import { v2 as cloudinary, UploadApiResponse } from 'cloudinary' import dotenv from 'dotenv' dotenv.config() ...

Unknown error occurred in Eventstore: Unable to identify the BadRequest issue

I'm encountering an error while using Eventstore, specifically: Could not recognize BadRequest; The error message is originating from: game process tick failed UnknownError: Could not recognize BadRequest at unpackToCommandError (\node_modul ...

Grouping elements of an array of objects in JavaScript

I've been struggling to categorize elements with similar values in the array for quite some time, but I seem to be stuck Array: list = [ {id: "0", created_at: "foo1", value: "35"}, {id: "1", created_at: "foo1", value: "26"}, {id: "2", cr ...

combine string inputs when ng-click is triggered

Is there a way to pass a concatenated string using ng-click to MyFunction(param: string)? I have tried but so far, no luck: <input id="MeasurementValue_{{sample.Number}}_{{$index}}" ng-click="Vm.MyFunction('MeasurementValue_{{sample.Number ...

Is there a way to create identical copies of data with the identical names?

Here is the code I have written: this.temp1.push(this.json); for(let i=0; i<this.temp1.length; i++){ if(this.temp1[i].name == this.json.name){ this.orderList[i] = this.json; this.DBorder[i] = this.order_json; } ...

Angular2 ERROR: Unhandled Promise Rejection: Cannot find a matching route:

I'm facing an issue with my Angular2 application while utilizing the router.navigateByUrl method. Within my component, there is a function named goToRoute, structured as follows: router.goToRoute(route:string, event?:Event):void { if (event) ...

Using TypeScript to define generic types for classes, method parameters, and method return types

I am facing an issue with this particular function function getCollection<T>(collectionType: T): Collection<T> { return new Collection<T>() } In the Collection class, I have the following code snippet export class Collection<T> { ...

Utilize the value of one variable to determine access to another variable in Javascript

I am working with several boolean variables and I want to create a new variable that keeps track of the most recently changed boolean variable. This way, every time a new boolean variable is modified, I can toggle the previous one. If you have any ideas o ...

Changing the target in tsconfig.json to "es2022" leads to the error message "Property 'xx' is referenced before its initialization.ts(2729)"

My Angular code is filled with instances where I assign a property at its definition like this... public data$ = this.service$.fetchData; constructor(private service$: MyService However, after updating my tsconfig.json target to "es2022", I encountered ...

Tips on effectively utilizing Chart.js with Typescript to avoid encountering any assignable errors

I'm encountering an issue while utilizing the Chart.js library in my Angular application with Typescript. The error message I'm receiving is as follows: Error: Object literal may only specify known properties, and 'stepSize' does not e ...

Enhancing TypeScript Native Interface Properties in TypeScript 2.4

After discovering an error in the native Typescript interface for HTMLTextAreaElement, I realized the need to make a correction. The current interface looks like this: interface HTMLTextAreaElement { setSelectionRange(start: number, end: number): void; ...

Angular2: The '@Component' decorator does not contain a 'directives' property in its configuration object

After creating a directive to auto-expand a textbox, I encountered an error when implementing it into the component. myAppComps.ts https://i.sstatic.net/rZHQc.png NPM RUN BUILD https://i.sstatic.net/DDY4k.png auto-grow.directives.ts https://i.sstat ...

Is there a way for Ionic to remember the last page for a few seconds before session expiry?

I have set the token for my application to expire after 30 minutes, and I have configured the 401/403 error handling as follows: // Handling 401 or 403 error async unauthorisedError() { const alert = await this.alertController.create({ header: 'Ses ...

Issue: Button ClickEvent is not triggered when the textArea is in onFocus mode

Is there a way to automatically activate a button ClickEvent when the textArea input is focused? Keep in mind that my textArea has some styles applied, causing it to expand when clicked. Here is an example: https://stackblitz.com/edit/angular-ivy-zy9sqj?f ...