Discovering the specific type of an object property in TypeScript

I am currently working on implementing a lookup type within an object. Imagine my object structure as follows:

class PersonList {
  persons = {
    john: 'description of john',
    bob: 'description of bob'
  }
}

I want to create a getter function that retrieves a person from the persons object without explicitly specifying it.

I came across the getProperty function in the documentation:

function getProperty<T, K extends keyof T>(obj: T, key: K) {
  return obj[key];  // Inferred type is T[K]
}

However, this function requires an obj parameter which I am looking to eliminate in my getter implementation. I attempted to use a proxy for the getter, but ran into issues:

class PersonList {
  persons = {
    john: 'description of john',
    bob: 'description of bob'
  };

  getPerson(name) {
    return this.getProperty(this.persons, name);
  }

  private getProperty<T, K extends keyof T>(obj: T, key: K) {
    return obj[key];  // Inferred type is T[K]
  }
}

Unfortunately, this approach did not throw an error when attempting something like

personList.getPerson('someonenotincluded');
, and autocomplete functionality was also not working correctly.

Answer №1

I would suggest taking the inline type provided and giving it a name (but feel free to continue reading if you prefer not to):

interface Persons {
  john: string;
  bob: string;
}

You can then utilize keyof Persons as the parameter type in the method getPerson:

class PersonList {
  persons: Persons = {
    john: 'description of john',
    bob: 'description of bob'
  };

  getPerson(name: keyof Persons) {
    return this.persons[name];
  }
}

Therefore, if pl is an instance of PersonList:

console.log(pl.getPerson('john')); // Works
console.log(pl.getPerson('someonenotincluded')); // Error

Live on the playground.

Alternatively, if you would rather keep it inline, you can achieve that by using keyof PersonList['persons'] as the parameter type:

class PersonList {
  persons = {
    john: 'description of john',
    bob: 'description of bob'
  };

  getPerson(name: keyof PersonList['persons']) {
    return this.persons[name];
  }
}

Live on the playground.


In a previous comment, you inquired:

Is it possible to implement this in an abstract class? ... It would be great to have the getter implemented in the abstract class, but I haven't figured out a solution yet.

...with reference to this code template:

abstract class AbstractPersonList {
  protected abstract persons: { [name: string]: string };
}

class Persons extends AbstractPersonList {
  persons = {
    john: 'this is john',
  }
}

class MorePersons extends AbstractPersonList {
  persons = {
    bob: 'this is bob',
  }
}

You could introduce a parameter in the AbstractPersonList class:

abstract class AbstractPersonList<T extends {[name: string]: string}> {
  protected abstract persons: T;
  public getPerson(name: keyof T): string {
    return this.persons[name];
  }
}

This leads to:

class Persons extends AbstractPersonList<{john: string}> {
  persons = {
    john: 'this is john',
  }
}

class MorePersons extends AbstractPersonList<{bob: string}> {
  persons = {
    bob: 'this is bob',
  }
}

Which results in the behavior you were seeking:

let n = Math.random() < 0.5 ? 'john' : 'bob';

const p = new Persons();
console.log(p.getPerson('john'));  // Works
console.log(p.getPerson('bob'));   // FAILS: Argument of type '"bob"' is not assignable to parameter of type '"john"'.
console.log(p.getPerson(n));       // FAILS: Argument of type 'string' is not assignable to parameter of type '"john"'.

const mp = new MorePersons();
console.log(mp.getPerson('john')); // FAILS: Argument of type '"john"' is not assignable to parameter of type '"bob"'.
console.log(mp.getPerson('bob'));  // Works
console.log(mp.getPerson(n));      // FAILS: Argument of type 'string' is not assignable to parameter of type '"bob"'.

Live on the playground.

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

Unable to modify the Express Request User type, however, I have the ability to incorporate new attributes to Request object

Encountering a familiar issue with what appears to be a simple fix. The Express Request object includes a user property that is specified as Express.User (an empty object). Attempting the common approach to redefining it: // index.d.ts import { User as P ...

The ActivatedRoute snapshot does not function properly when used in the TypeScript class constructor

Currently, I am encountering a challenge with TypeScript and Angular 2. The structure of my TS class is as follows: 'import { Component, OnInit } from '@angular/core'; import {ActivatedRoute} from '@angular/router'; @Component({ ...

Jasmine : Techniques for monitoring a method callback using method.then()

Within my Angular 4.0.0 application, I have a method called in my component. This method is invoked within a service: this.myService.myMethod(param).then(any => { console.log("success case"); }) .catch(error => { console.log("error"); }); ...

Arrangement of code: Utilizing a Node server and React project with a common set of

Query I am managing: a simple react client, and a node server that functions as both the client pages provider and an API for the client. These projects are tightly integrated, separate TypeScript ventures encompassed by a unified git repository. The se ...

Guide to Setting Up "Remember Me" Login for Users in Angular

I am having trouble setting the 'Remember Me' option on my Login page. I tried using localstorage session but it seems like something is missing in the service file that's causing it not to respond properly. I attempted to follow a guide on ...

Is implementing client components in Server Side pages an effective strategy for optimizing SSR performance?

In order to overcome the challenge of using client-side components in server-side pages, I made the decision to create a client-side wrapper to encapsulate these components within server-side pages. This way, I can manage all API calls and data fetching on ...

Separate angular structure into various sections

I am developing a form builder using Angular dynamic form functionality. The form data is loaded from a JSON object, as shown below: jsonData: any = [ { "elementType": "textbox", "class": "col-12 col-md-4 col-sm-12", "key": "first_ ...

Error encountered when initializing a variable within the constructor of a TypeScript file in Angular 4

This is the content of my app.component.html file PL Auth Username: Password : Generate OTP Enter OTP : Login This is the code in my app.component.ts file import { Component, OnInit } from '@angular/core' ...

Creating a TypeScript function that utilizes generics to automatically infer the return type

How can I create a function with a generic argument that can return any type, and have the return type inferred from its usage? I attempted the following code: type Thing<T> = <U>(value: T) => U const shouldMakeStrings: Thing<string> ...

What is the reason behind the error Generic indexed type in Typescript?

Here is a scenario where I have a specific generic type: type MapToFunctions<T> = { [K in keyof T]?: (x: T[K]) => void; }; It functions correctly in this instance: type T1 = { a: string }; const fnmap1: MapToFunctions<T1> = { a: (x: st ...

Discover the power of catching Custom DOM Events in Angular

When working with an Angular library, I encountered a situation where a component within the library dispatches CustomEvents using code like the following: const domEvent = new CustomEvent('unselect', { bubbles: true }); this.elementRef.nati ...

Status:0 was received as the response from URL:null during the REST call made from my iOS Ionic application

I am currently facing an issue with a rest call in my Ionic app. The call works fine on Android devices but encounters problems on iOS devices. Below is the implementation of the rest call in my Ionic service. import { Http } from '@angular/http&apos ...

In my coding project using Angular and Typescript, I am currently faced with the task of searching for a particular value within

I am facing an issue where I need to locate a value within an array of arrays, but the .find method is returning undefined. import { Component, OnInit } from '@angular/core'; import * as XLSX from 'xlsx'; import { ExcelSheetsService } f ...

Building and executing an Angular 2 program on the Windows platform: Step-by-step guide

After successfully installing npm and related packages including TypeScript and Angular 2, I am encountering difficulties running Angular 2 in my browser on a Windows platform. Can someone provide a step-by-step guide to help me create and run Angular 2 ...

The cache does not contain '.chunk-`X`' as requested in Next.js error

Hello everyone, I've encountered a recent issue with my code that previously worked fine. I was using getStaticProps with a cache time of 5 days, but now I'm facing an error related to the title. Here is a more detailed look at the error: error ...

Problems arising from the layout of the PrimeNG DataView component when used alongside Prime

I've been working with a PrimeNG DataView component that requires the use of PrimeFlex's flex grid CSS classes to set up the grid structure. One of their examples includes the following instructions: When in grid mode, the ng-template element ...

Removing an image from the files array in Angular 4: A step-by-step guide

I have recently started working with typescript and I am facing a challenge. I need to remove a specific image from the selected image files array before sending it to an API. app.component.html <div class="row"> <div class="col-sm-4" *ngFor ...

New post: "Exploring the latest features in Angular

Looking for help with integrating Angular and SpringREST to fetch data from the backend? Here's my situation: I need to retrieve a JSON string from the backend using a POST request, send it to my site's hosted link, and display it on the user int ...

Customize back button functionality in Ionic 2

Is it possible to modify the behavior of the back button shown in this image? I would like to specify a custom destination or perform an action before navigating back, instead of simply returning to the previous page. https://i.stack.imgur.com/EI2Xi.png ...

Listening to changes in a URL using JQuery

Is there a way to detect when the browser URL has been modified? I am facing the following situation: On my webpage, I have an iframe that changes its content and updates the browser's URL through JavaScript when a user interacts with it. However, no ...