Maintaining data types with Object.keys()

My challenge involves an object with typed keys referred to as Statuses (StatusesType). The task is to iterate over the object and pass keys to a method that expects parameters of the same type, let's call it statusPrinter().

type StatusesType = 'PENDING' | 'APPROVED' | 'REJECTED';
type SomeMap = {
    [key in StatusesType]?: number
}

const STATUSES: SomeMap = {
    PENDING: 5,
    REJECTED: 2,
};

function statusPrinter(val: StatusesType) {
    console.log('- ', val);
}

Object.keys(STATUSES).forEach(status => {
    statusPrinter(status);
});

However, TypeScript throws an error when I use statusPrinter(status);, stating:

error TS2345: Argument of type 'string' is not assignable to parameter of type 'StatusesType'.

The question now becomes how can I pass this key while preserving its original type?

I am aware of the workaround using

statusPrinter(<StatusesType>status);
, but I would prefer a more native solution if possible.

Update: If maintaining type consistency during iteration over object keys using Object.keys() proves impossible, what other alternatives exist? Is there a way to iterate over keys while preserving types, and if so, which approach is recommended? While I am open to options beyond Object.keys(), preserving the original object structure is ideal.

Thank you!

Answer №1

Concise and safe solution utilizing the in-built ES2015 Map feature:

type StatusesType = 'PENDING' | 'APPROVED' | 'REJECTED';

const STATUSES = new Map<StatusesType, number>([
    ['PENDING', 5],
    ['REJECTED', 2],
]);

function printStatus(val: StatusesType) {
    console.log('- ', val);
}

STATUSES.forEach((_, status) => printStatus(status));

Answer №2

When using Object.keys, it will provide an array containing keys that are all of the type string.

The signature for Object.keys would therefore be

key(object: {}): Array<string>
. This means that as you iterate through the keys, the variable status will be a string and not a StatusesType.

If needed, you can explicitly specify the type by casting like so:

statusPrinter(status as StatusesType)

For further information, please refer to:

  • Typescript: cast an object to other type

Answer №3

To achieve this, you can use an iterator function like the following example:

function iterateOverMap<T, K extends keyof T>(map: T, callback: (key: keyof T, value: T[K]) => void) {
  Object.keys(map).forEach((key: K) => callback(key, map[key]));
}

iterateOverMap(STATUS_MAP, statusItem => {
    printStatus(statusItem);
});

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

Incorporate a background image into mat-dialog

I've been struggling to set a background image on my mat-dialog, but for some reason it's not showing up at all. I attempted using a panelClass as well, but still no luck. .custom-panel .mat-dialog-container { background-image: url("../. ...

Convention for Naming Files in Typescript

Can anyone provide guidance on file-naming conventions specifically for a Typescript file dedicated to storing types and interfaces? I have come across various Typescript Coding Convention projects on GitHub which cover general file-naming conventions her ...

To dismiss a popup on a map, simply click on any area outside the map

Whenever I interact with a map similar to Google Maps by clicking on various points, a dynamically generated popup appears. However, I am facing an issue where I want to close this popup when clicking outside the map area. Currently, the code I have writte ...

Identifying Shifts in Objects Using Angular 5

Is there a way to detect changes in an object connected to a large form? My goal is to display save/cancel buttons at the bottom of the page whenever a user makes changes to the input. One approach I considered was creating a copy of the object and using ...

MUI DataGrid Identifying Duplicate Rows

I'm encountering an issue with my Data Grid component from MUI when fetching data using axios. The console shows the correct data, but on the page, it only displays one result or duplicates. I suspect there might be a frontend problem, but I'm s ...

Design a unique TypeScript index type with properties `[key of Y]: Partial<X>` that, when paired with a `default: Partial<X>` property, do not remain partial themselves

Here are some TypeScript type definitions to consider: enum Environment { Local = 'local', Prod = 'prod' } type EnvironmentConfig = { isCustomerFacing: boolean, serverUrl: string } type DefaultBaseConfig<T> = { default ...

In my experience with Angular 8, I have found that the ViewChild() method is successful when used with an array, but does not work

How do I achieve the following functionality: I want a child component to have an input field and a SEND button. When the button is clicked, the value entered in the input field should be displayed in the parent component. This approach currently works: ...

Guidelines for converting an array into checkboxes using React Native with TypeScript

As I embark on my React Native journey, I have chosen to use TypeScript in my project. Currently, I am faced with the challenge of mapping an array into a checkbox. Enclosed below is a snippet from my JSON file: { "stud_name": "Adam", "sex": "male" ...

Seamless database migrations using sequelize and typescript

I've been exploring the concept of generating migration files for models that already exist. When I use the "force: true" mode, tables are automatically created in the database, so I find it hard to believe that creating migration files automatically ...

Creating an overloaded callable interface using TypeScript

The thread on implementing a callable interface provides some helpful information, but it doesn't fully address my specific query. interface lol { (a: number): (b: number) => string // (a: string): (b: string) => string // overloaded wi ...

Tips for creating dynamic amd-dependencies in TypeScript

Is there a way to dynamically load a Javascript language bundle file in Typescript based on the current language without using static methods? I want to avoid having to use comments like this for each bundle: /// <amd-dependency path="<path_to_bund ...

You can only import Global CSS from your Custom <App> and not from any other files

Encountered the following error: ./styles/globals.scss Global CSS cannot be imported from files other than your Custom <App>. Due to the Global nature of stylesheets, and to avoid conflicts, Please move all first-party global CSS imports to pages/_ ...

Angular validation is malfunctioning for fields that have names ending with periods

Currently in the process of generating dynamic input fields <input class="form-control-lg form-control" placeholder="{{data.DisplayName}}" formControlName="{{data.labelName}}" type="text" maxlength="13" ...

Expanding a class in Typescript by adding a function with the same name but varying properties and types

class A { play(a: string): string{ return a; } } class B extends A { play(c: string, b: number): string{ return c + ' ' + b.toString(); } } let x = new A(); console.log(x.play('John')); let y = new B(); console.lo ...

Exploring the functionality of two-way data binding in Angular - a beginner's guide

Transitioning from a different framework and switching from JavaScript to Angular & TypeScript has left me feeling confused about how to efficiently share data/values between components. ...

Viewing an image from a local file on a web browser

I am currently working on a project where I want the user to be able to select a local image that will then be displayed on the page. As someone who is new to web development, I did a lot of research and found some helpful information on StackOverflow. I t ...

When I try to install dependencies with Hardhat, the "Typechain" folder does not appear in the directory

After installing all the dependencies, I noticed that the "typechain" folder was missing in the typescript hardhat. How can I retrieve it? Try running npm init Then, do npm install --save-dev hardhat Next, run npx hardaht You should see an option to se ...

Creating a typescript array with values matching keys in an object: How to do it?

How can I define MyInterfaceKeys in the given code? interface MyInterface extends Record<string, any> { Appearance?: "default" | "primary" | "link"; Size?: "small" | "medium" | "large" ...

What is the correct method for retrieving a specific child element in React?

In my React project, I have created a component that consists of various subcomponents: import React, { FunctionComponent } from 'react'; import { FormControl, FormGroup, FormGroupProps, FormLabel, FormText, FormTextProps } from 'react-boots ...

Utilizing Angular 7 to extract data from the initial column of an Excel spreadsheet and store it within an array

Currently, I am in the process of uploading an excel file that contains an ID column as its first column. My goal is to extract all the IDs and store them in an array for future data management purposes. To accomplish this task, I am utilizing the XLSX l ...