Using Typescript to determine the data types based on the specific object keys

Imagine having a type defined as:

type Foo = {
  foo: number;
  bar: string;
  baz: boolean;
}

The goal is to create a type Buzz that can determine the value type for a specific key, such as:

const abc: Buzz<Foo> = {
  key: 'foo',
  formatter: (detectMe) => {} //The expected result is TS inferring 'number' here
};

When providing the key 'foo', the parameter in formatter should be inferred as number. Various attempts were made:

interface ColumnDescription<T> {
  label: string;
  key: keyof T;
  formatter?: (datum: T[keyof T]) => void;
}

Unfortunately, this leads to the argument being inferred as number | string | boolean.

An alternative approach was also tried:

interface ColumnDescription<T, K extends keyof T> {
  label: string;
  key: K;
  formatter?: (datum: T[K]) => void;
}

This solution works but requires specifying the key in the second type argument every time, instead of it happening automatically. For instance:

const abc: Buzz<Foo, 'foo'> = { //I want to avoid specifying the key
  key: 'foo',
  formatter: (detectMe) => {} //This inference is correct
};

Answer №1

In the comment I provided, I recommend

type Buzz<T> = {
  [K in keyof T]-?: { key: K; formatter: (d: T[K]) => void }
}[keyof T];

This approach is similar to using Buzz<T, K extends keyof T>, but instead of requiring K to be specified for Buzz, I utilized a mapped type {[K in keyof T]: ...} which automatically loops through keys in keyof T and constructs a new object with the same keys, but with values that match the types you are seeking. This means to achieve the desired Buzz<T>, we have to look up the property values by indexing into it with [keyof T]. Consequently, Buzz<T> contains a union of types where each component corresponds to your Buzz<T, K extends keyof T> for a specific key K.

Let's validate its functionality:

const abc: Buzz<Foo> = {
  key: "foo",
  formatter: detectMe => {} // inferred as number, as intended
};

The output appears correct, and let's examine the type of abc using IntelliSense:

const abc: {
    key: "foo";
    formatter: (d: number) => void;
} | {
    key: "bar";
    formatter: (d: string) => void;
} | {
    key: "baz";
    formatter: (d: boolean) => void;
}

Everything seems to be in order.

I hope this explanation is helpful. Best of luck!

Link to code

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

Using Angular to create a dynamic form with looping inputs that reactively responds to user

I need to implement reactive form validation for a form that has dynamic inputs created through looping data: This is what my form builder setup would be like : constructor(private formBuilder: FormBuilder) { this.userForm = this.formBuilder.group({ ...

Subtracted TypeScript concept

Is it possible to create a modified type in Typescript for React components? import {Component, ComponentType} from 'react'; export function connect<S, A>(state: () => S, actions: A){ return function createConnected<P>(componen ...

Can you provide guidance on implementing Material-UI's `withStyles` decorator in a practical scenario?

I'm currently solving the challenge of annotating the types for the different styles in my code. After converting from plain JavaScript to TypeScript, I am now adding type annotations. Here is a snippet of the code: import * as React from 'react ...

When passing parameters through a URL in TypeScript, the display shows up as "[object object]" rather than as a string

Hey there! I'm trying to pass some string parameters to my URL to fetch information from an API. Everything seems fine, and when displayed in an alert, the URL looks exactly as it should (no [object, object] issue). var startDate = "2020-09-20"; var ...

A custom type in Typescript used as a key in a key-value pair

Here is a key-value pair used for a filtering system. The filter can be merged with current filters or applied by resetting the previous ones. type MINE = "mine" type BOOKMARKED = "bookmarked" type TEXT_QUERY = "textQuery" typ ...

Managing errors with async/await in an Angular HttpClient function

I have been experimenting with an async/await pattern to manage a complex scenario that could potentially result in "callback hell" if approached differently. Below is a simplified version of the code. The actual implementation involves approximately 5 co ...

Refresh a reactive form in Angular Material

I'm facing a challenge with resetting my form after data submission. Everything is working except for validating the email format. Using this.form.reset() doesn't seem to resolve the issue. https://i.sstatic.net/QRZEa.png Any suggestions on how ...

I'm having trouble linking MikroORM migration to Postgresql - the npx command keeps failing. Can anyone offer some guidance on what

I am encountering a situation similar to the one described in this post. I'm following Ben Awad's YouTube tutorial: you can see where I am in the tutorial here. Objective: My goal is to execute npx mikro-orm migration:create in order to generate ...

invoke the next function a different privateFunction within rxjs

I'm trying to figure out how to pass the resetPassword data to the _confirmToUnlock method in Typescript/RxJS. Here is my subscribe method: public invokeUnlockModal() { let resetPassword = { userName: this.user?.userName}; //i need to send this ...

Using the Typescript type 'never' for object fields: a guide to implementing it

I'm attempting to make this specific example function similar to this one: interface Foo { a: number; b: string; c: boolean; } type Explode<T> = keyof T extends infer K ? K extends unknown ? { [I in keyof T]: I extends K ? T ...

Typescript and React encounter an error when trying to call a nested map function, stating that this expression is

Currently, I am working on a project using Typescript with React and encountering an issue with returning JSX from a function. Generally, I have not faced any problems with a nested map loop, but for some reason, I am getting an error when using Typescript ...

The `process` variable is not recognized in a Vue/TypeScript component

I've encountered an issue trying to use .env variables in my Vue app. When I ran npm install process, the only syntax that didn't result in an error when importing was: import * as process from 'process'; Prior to this, I received the ...

Invoking the callback function within the containing scope in Typescript

I am facing an issue with my Angular component where I have a class that includes common services and functions. While passing some functions as callbacks, the scope is getting lost during execution. Let me demonstrate the problem through the code below: @ ...

When combining Jest async tests with mongodb-memory-server, an issue arises where the test consistently times out

I'm currently facing an issue with running my async jest tests properly while using the mongodb-memory-server package. In my code, I have a beforeAll function that connects to a memory mongo database: beforeAll(async () => await connect()); Follow ...

What is the process for declaring a member variable as an extended type in TypeScript?

Is it possible to declare a "member variable" as an "extension object" rather than a static type (without relying on an interface)? Imagine something like this pseudocode: class Foo { bar -> extends Rectangle; constructor(barInstance:IRec ...

The property 'owlDateTimeTrigger' cannot be bound to 'span' as it is not recognized

I have integrated the OwlDateTimeModule into my smart-table-datepicker component. Although I imported it in my smart-table-datepicker.module file, I am still encountering errors. What could be causing this issue? smart-table-datepicker.module.ts import { ...

Guide to updating component after closing MatDialog and updating data in database using Angular 6

Currently, I am in the process of learning a MEAN stack app with Angular 6. My main focus right now is on refreshing the component after making any changes, such as adding or updating new clients/cars/drivers/bookings. The issue I'm facing is that aft ...

Issue encountered: Inability to locate the module or its associated type declarations while working with a monorepo and @typescript

This problem seems straightforward, but finding a solution has been tricky... Whenever I try to use @typescript-eslint/utils, I encounter the error message Cannot find module @typescript-eslint/utils or its corresponding type declarations. Here is the st ...

gulp-typescript compiler encounters issues with the readonly keyword causing errors

Recently, I updated my application to use the latest versions of Angular 2 rc.6 and Angular Material 2 alpha 8-1. These updates require typescript 2, with the latter introducing the new readonly modifier. To compile my .ts files, I rely on gulp-typescript ...

Error in Typescript due to delegate function not being recognized post minification

Here is a code snippet that uses delegate: <pre> $.ajax(this.validateURL, { type: "post", url: this.validateURL, data: JSON.stringify(i), contentType: "application/json; charset=utf-8", dataType: "json", success: i => t.pro ...