How to iterate over a specific property of a class using TypeScript

My goal is to iterate over specific keys of a class without using the index signature [key:string]:any as it is not the recommended approach.

This is my proposed solution:

interface I {
    a: string,
    b: number
}

type NullKeysOf<T> = {
    [P in keyof T]: null
}

type PartialNullKeysOf<T> = Partial<NullKeysOf<T>>;

const obj:PartialNullKeysOf<I> = {
    a:null
}

class A<M extends I> implements I{
    a:string;
    b:number;
    obj:PartialNullKeysOf<M>
    constructor(a:string, b:number, obj:PartialNullKeysOf<M>){
        this.a = a;
        this.b = b;
        this.obj = obj;
    }
    public loop(){
        for(const k in this.obj){
            console.log(this[k]);
        }
    }
}

const a = new A<I>('',3,obj);

a.loop();

Check out the TypeScript Playground here

I encountered an error message:

Type 'Extract<keyof M, string>' cannot be used to index type 'this'.

I am puzzled by why the type of k in the loop is Extract<keyof M, string>. Shouldn't it be typeof I instead?

Answer №1

Why is the type of 'k' in the loop specified as Extract<keyof M, string>?

You defined the member 'obj' as 'PartialNullKeysOf<M>'. The 'for...in' loop iterates through the 'string' keys of the object, hence the type of 'k' is determined as "retrieve all string keys from a given value of type M":

  1. keyof M provides the key types present in M (string | number | symbol union)
  2. Extract filters out only the keys of type string (as the second generic parameter)
  3. The generic class type parameter in use is M, not I (although constrained by I)

Combining the above information leads to 'k' being inferred as Extract<keyof M, string>

Shouldn't it be typeof I instead?

No, it should not. Refer to point 3. The 'extends' keyword in generic type parameters does not imply inheritance, but rather focuses on the compatibility of types. 'M' is simply verified for compatibility with 'I'.

Type 'Extract<keyof M, string>' cannot be used to index type 'this'

As mentioned earlier, there is no direct correlation between 'I' and 'M': just because you know they are equivalent, does not grant the compiler the ability to safely assume so. Luckily, you can bypass the need for type assertions:

public loop(this: A<M> & M){ 
        for(const k in this.obj){
            console.log(this[k]); //OK
        }
    }

The this parameter guarantees that the original type of this (A<M>) remains intact, while explicitly informing the compiler about the members of type M within this.

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

Typescript is throwing an error with code TS2571, indicating that the object is of type 'unknown'

Hey there, I'm reaching out for assistance in resolving a specific error that has cropped up. try{ } catch { let errMsg; if (error.code === 11000) { errMsg = Object.keys(error.keyValue)[0] + "Already exists"; } return res.status ...

Disabling the Angular router link

I'm currently working on an Angular application that utilizes routing and auth guards. Check out the code on StackBlitz View the app component HTML here <div class="container"> <div class="row"> <div class="col-xs-12 col-sm-10 ...

Make sure to always keep all stars contained within a div element

How can I keep five stars inside a div even when the screen size is small? I have created a div with an image and I want to place five stars within that div. However, as I reduce the size of the screen, the stars come out of the box. Is there a way to en ...

Issue encountered with Angular 13 and Twilio Sync: The variable name is not recognized as a constructor, resulting in

After upgrading to angular 13, I encountered a problem that was not present when using angular 10. In my TwilioSyncService, the require statement is included in the constructor because it is an Injectable service requirement. The code snippet shows how t ...

Encountered an issue loading resource: net::ERR_BLOCKED_BY_CLIENT while attempting to access NuxtJS API

After deploying my NuxtJS 2 app on Vercel and adding serverMiddleware to include an api folder in the nuxt.config.js file, everything was working smoothly. However, when I tried making an api call on my preview environment, I encountered an error: POST htt ...

Retrieving the chosen option from a personalized drop-down element

I have been working on a project using Angular 2, where I created a dropdown component with the following code: @Component({ selector: 'dropdown', template: ` <div class="row" > <div class="col-sm-3"> ...

What is the best way to display my images within Material UI Cards using React with Typescript?

I'm currently faced with a challenge of rendering images within Material UI's cards. I am successfully passing props to each card from a constants.tsx file where the heading, description, and bodyHeader are all properly read, but for some reason, ...

Rule of authentication using Firebase Database

I need to establish a rule in my Firebase Database to prevent unauthorized access for reading and writing purposes. Within my database, there is a collection of words, each containing a "uid" field that corresponds with the uid of the authUser key stored ...

Performing an insertion in TypeORM with a foreign key connection

In my database schema, I have set up a relationship where each Chatroom can have multiple Messages linked to it. However, when I try to insert a Message (or a batch of Messages), the foreign key for ChatRoom is not being assigned properly and remains null. ...

The SortKey<> function is ineffective, even though the individual types it uses work perfectly fine

After my initial inquiry about TypeScript, the focus shifted to this current topic. In my previous question, I was attempting to develop a generic sort() method that could function with an array of sort keys defined by the SortKey type featured there (and ...

What is the best way to condense this code snippet into just a single line?

I am currently working with an array of objects and my main objective is to eliminate duplicates. I have implemented a dictionary as a "filter" mechanism but I am struggling to find alternative ways to refactor this process. I am aware that there must be a ...

Error429 was received from a GET request made to the Imgur API

Encountering a Request failed with status code 429 error from the Imgur API despite using a new Client_ID that hasn't been used before, Here is my Api.ts: const imgurClientId = process.env.NEXT_PUBLIC_Client_ID const BASE = "https://api.imgur. ...

Using Typescript to change a JSON array of objects into a string array

I'm currently working with the latest version of Angular 2. My goal is to take a JSON array like this: jsonObject = [ {"name": "Bill Gates"}, {"name": "Max Payne"}, {"name": "Trump"}, {"name": "Obama"} ]; and convert it into a st ...

I am looking for assistance in achieving 100% code coverage with this code. Even just verifying if the function has been executed will suffice

I'm struggling to figure out how to access the remaining line of code in order to achieve full code coverage. I am specifically looking to check if the function has been called using "toHaveBeenCalled()". Below are the TypeScript file and my Spec fil ...

Utilizing LocalStorage with Angular 6 BehaviorSubject

I'm struggling with retaining data after refreshing a page. My approach involves using a shared service to transfer data between unrelated components. Despite extensive research on LocalStorage implementation and usage, I have not been able to find a ...

Is it possible to create generic types for type predicate functions in TypeScript?

While attempting to create a function for checking generic types, I encountered an unusual error during my research. Despite searching on Google, I wasn't able to find much information, so now I'm curious if it's feasible to accomplish the f ...

What is the purpose of adding a missing import in VSCode and why does it open a new tab with

Hey there! I've been experiencing an issue with my IDE VSCode for the past couple of weeks. Previously, everything was working fine but now I'm facing a peculiar problem. Whenever I miss an import in VSCode while working on my Angular project, i ...

When attempting to save my submission object data to the database, TypeORM unexpectedly alters the information

I am encountering an issue with inserting my data into a database using TypeORM The problem at hand is as follows: What needs to be sent to the database includes the following data: Title, Description, Userid, idCategoryService, and createdBy. The ids and ...

Using a class as an interface in TypeScript is a common practice when a constructor is

Consider a scenario where I have a class structured like this: class MyClass { a: string } Now, let's say I create a variable with the following definition: let obj: MyClass = { a: 2 } An error will be triggered in Typescript because 2 is not ...

When an error occurs while trying to execute a promise more than once, the message "Attempting to access an undefined property

Currently, I am tackling asynchronous issues by using promises. The strange thing is that when I run the promise for the first time, everything works perfectly. However, if I execute the same function twice, it throws a "Cannot read property of undefined" ...