Creating a typescript object shape without an index signature involves specifying the exact properties

I have a query regarding a potential design gap in TypeScript. Consider a function that accepts objects meeting a specific interface:

interface Params {
    [key: string]: string | number | boolean | undefined | null;
}

This interface specifies that the keys must be strings and the properties can be primitive types or void.

If I define another method that takes an interface fulfilling the Params interface, I encounter an error stating that the other interface lacks an index signature. An example of such an interface could be:

interface Foo {
    bar: string;
}

Even changing the signature to

Record<string, string | number | boolean | undefined | null>
does not resolve the missing index signature issue.

A snippet of code demonstrating this scenario is shown below. It is essential to specify the key and value type of the object for certain operations with Object.entries:

function specificFunction(obj: Foo) {
  genericFunction(obj);
}

function genericFunction(params: Params) {
  Object.entries(params).forEach(([key, value]) => {
    …
  })
}

EDIT: It is crucial that the behavior of the specificFunction remains unchanged, as it serves to narrow down the allowed interface. This restriction ensures specific properties are present in objects to achieve a desired outcome.

Answer №1

genericFunction requires a type with an index signature.

The default behavior for Foo does not include an index signature because it is defined as an interface.

However, there is a workaround. If you declare Foo using the type keyword instead of interface, it will work.

Why?

This is because types defined with the type keyword have index signatures by default.

Please refer to this answer for more insights.

Therefore, the following code will compile:

interface Params {
    [key: string]: string | number | boolean | undefined | null;
}

// use type here instead of interface
type Foo = {
    bar: string;
}

function specificFunction(obj: Foo) {
  genericFunction(obj);
}

function genericFunction(params: Params) {
  Object.entries(params).forEach(([key, value]) => {

  })
}

Playground

UPDATE 2 If you don't have control over Params and Foo, you can use the following utility type:

interface Params {
    [key: string]: string | number | boolean | undefined | null;
}

interface Foo {
    bar: string;
}

type Values<T> = T[keyof T]

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

function specificFunction(obj: MakeIndexed<Foo>) {
    genericFunction(obj);
}

function genericFunction(params: Params) {
    Object.entries(params).forEach(([key, value]) => {

    })
}

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

"X is not compatible with these types of property," but it is not the case

I attempted to instantiate an interface object with properties initialized from another object as follows: id: data.reference.id Even though the properties are compatible, the TypeScript compiler is throwing an error. I am confused about why this is happ ...

Working with e.charcode in TypeScript allows for easy access to

I'm having trouble understanding why this code snippet is not functioning as expected. const addRate = (e: { charCode: KeyboardEvent }) => { if (e.charCode >= 48) { ... } } The error message I receive states: 'Operator '>=& ...

Office-Js Authentication for Outlook Add-ins

I am currently developing a React-powered Outlook Add-in. I kickstarted my project using the YeomanGenerator. While working on setting up authentication with the help of Office-Js-Helpers, I faced some challenges. Although I successfully created the authen ...

Is there a way to revert my Ionic CLI back to the previous version that I had installed?

Having just updated to version 3.2.0, I am encountering numerous issues, such as the malfunctioning of the ionic serve command. ...

The placeholder within my input moves up and down when switching the input type from password to text

Currently, I am encountering an issue with the styling of a standard input element in React. Specifically, the placeholder text moves up and down by about 2px when viewed on Chrome, while there are no problems on Safari. How can I go about resolving this i ...

Angular 4/2: Exploring the Concept of Method Overloading

Currently, I am working on Angular 4 and have been struggling to find a suitable solution for method overloading in Angular 2 or 4. Can we actually implement method overloading in an Angular service class? I would really appreciate if someone could provide ...

How should one properly assign an element type provided as an argument?

I'm attempting to define a type for an element passed as a parameter using React.ComponentType. import * as React from "react" type BaseType = { element: React.ComponentType } const Base = ({element: Element}: BaseType) => ( <Ele ...

Angular: Tailoring the Context Menu

Currently, I am utilizing a helpful tutorial to implement a custom context menu feature. The main issue I am facing is that when a user interacts with the list items, I want the correct index of each item to be displayed. However, at the moment, clicking o ...

Tips for accessing the type of a nested union in TypeScript

My graphql codegen has produced this type for me: export type GetOffersForMembershipQuery = { __typename?: "Query"; offers: | { __typename?: "BaseError" } | { __typename?: "QueryOffersSuccess"; data ...

Is it possible to implement Angular Universal on Github Pages?

Is it doable to Deploy Angular Universal on Github Pages? I've come across some solutions such as angular-cli-ghpages, but from what I understand, these options don't pre-render content for SEO purposes. ...

What could be the reason for my Angular 2 app initializing twice?

Can someone help me figure out why my app is running the AppComponent code twice? I have a total of 5 files: main.ts: import { bootstrap } from '@angular/platform-browser-dynamic'; import { enableProdMode } from '@angular/core'; impor ...

I'm unable to modify the text within my child component - what's the reason behind this limitation?

I created a Single File Component to display something, here is the code <template> <el-link type="primary" @click="test()" >{{this.contentShow}}</el-link> </template> <script lang="ts"> imp ...

Error encountered: Unable to locate module 'psl'

I'm encountering an issue when trying to execute a pre-existing project. The error message I keep receiving can be viewed in the following error logs image Whenever I attempt to run "npm i", this error arises and I would greatly appreciate it if some ...

Constructing a hierarchical tree structure using an array of objects that are initially flat

My goal is to create a hierarchical tree structure from a flat array: The original flat array looks like this: nodes = [ {id: 1, pid: 0, name: "kpittu"}, {id: 2, pid: 0, name: "news"}, {id: 3, pid: 0, name: "menu"}, {id: 4, pid: 3, name: ...

Verify if an object property is called with the toHaveBeenCalledWith() function in Jasmine

Recently started incorporating Jasmine into my workflow and I am trying to verify if my method was called with an object that includes a MyProperty property. Currently, my setup looks like this: expect(service['method']).toHaveBeenCalledWith(jasm ...

Retrieve the value of [routerLinkActive] in the component's class

Recently, I've been working on a tab component called TabComponent and it includes the following HTML template: <a [routerLink]='link' [routerLinkActive]="[is-active]">link label</a> <button>Close tab</button> The c ...

Executing npm and ng commands via an Ant script on a Windows machine leads to the error message "The specified file could not be found."

When attempting to execute the following Ant script, which runs the "npm" command: <target name ="test"> <exec executable="npm" failonerror="true"> <arg value="install" /> </exec> </target> An error occurs, i ...

Achieve the capability to upload multiple files in Next.js using the upload.io integration feature

I'm currently using upload.io for uploads and replicate.com for an AI model on a specific app. I am able to upload one picture, but unfortunately, I am encountering issues when trying to upload multiple pictures. Can anyone identify the problem here? ...

Can the grunt command be executed automatically after saving code in TypeScript?

As a newcomer to FrontEnd and JavaScript coding in TypeScript, I find myself constantly needing to follow these steps after making a code change: save the code -> compile it using Grunt -> reload the webpage. It can be quite time-consuming. Is there ...

Using Typescript with Gulp 4 and browser-sync is a powerful combination for front-end development

Could use some assistance with setting up my ts-project. Appreciate any help in advance. Have looked around for a solution in the gulpfile.ts but haven't found one yet. //- package.json { "name": "cdd", "version": "1.0.0", "description": "" ...