Broaden the TypeScript interface with indexed types

Imagine a straightforward indexed interface:

interface FormData {
    [K: string]: string;
}

This little fella works like a charm. However, there comes a time when I want to allow a property to be an array of strings.

interface AcmeFormData extends FormData {
    foobar: string[];
}

Typescript throws an error stating

Property 'foobar' of type 'string[]' is not assignable to string index type 'string'.

After checking the documentation, it appears that the following should work, but it also raises concerns.

interface FormData {
    [K: string]: string;
    foobar: string[];
}

I want to mention that I'd prefer to steer clear of using a union type ([K: string]: string | string[];) because most of the time, the data will only be a single string value and therefore I would rather avoid adding type hints.

Is this doable? Or am I trying to push the limits of Typescript?

Answer №1

To achieve this, consider using an intersection instead of the extends keyword. For instance:

interface FormData {
    [K: string]: string;
}

type AcmeFormData = FormData & { foobar: string[] };

declare const example: AcmeFormData;

example.foobar       // string[]
example.anythingelse // string

However, be cautious as this approach can lead to inaccuracies in index signatures. TypeScript may infer incorrect types based on the modified signature:

for (let key in example) {
    // The value 'val' is inferred as type string, but beware!
    // It will actually be a string[] for the 'foobar' key.
    // TypeScript won't recognize this, causing runtime errors even though it compiles without issues.

    const val = example[key].toLowerCase();
}

Answer №2

The issue with the current setup arises from using [K: string]: string in the interface, which mandates that all keys must have string values including foobar. To resolve this, I suggest structuring it as follows:

interface NewData {
  parameters: { [param: string]: string }
  additionalInfo: number[]
}

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

Angular 2 is throwing an error: Unhandled Promise rejection because it cannot find a provider for AuthService. This error is occurring

My application utilizes an AuthService and an AuthGuard to manage user authentication and route guarding. The AuthService is used in both the AuthGuard and a LoginComponent, while the AuthGuard guards routes using CanActivate. However, upon running the app ...

Error: Attempting to initiate a backward navigation action while already in the process. Utilizing Natiescript

I encountered an issue with the routing code in my Nativescript app. Here is the code snippet: const routes: Routes = [ { path: 'home', component: HomeComponent, canActivate: [AuthGuard], children: [ {path: 'fp&apos ...

:host background color may be missing, but the font size has been boosted?

Check out this demo where the CSS is applied to the :host element or <hello>. The font size increases but the background color remains unchanged. What do you think? styles: [` :host { font-size: 2rem; background-color: yellow; }`] }) ...

Determine the data type of a parameter by referencing a prior parameter

Consider a scenario in my software where I have two distinct implementations of an Event Emitter. For instance: type HandlerA = (data: boolean) => void; type HandlerB = (data: number) => void; // HandlerB is somehow different from HandlerA type Eve ...

Iterate through each element in the array using headlessui tabs for mapping

I am struggling to find a way to display all items from the array on every tab in my project. Currently, I can show items by category but I need to figure out how to display all items across all tabs. My expectation was to showcase all items on each tab. ...

An issue has occurred with error code TS2688: The type definition file for 'jquery' cannot be located. [Angular Application] --

I am currently working on developing an Angular web application with a specific theme that requires the inclusion of CSS and JS files. Majority of the JS files needed are jquery plugins, so I made sure to install them using the following commands: npm i j ...

PhpStorm IDE does not recognize Cypress custom commands, although they function properly in the test runner

Utilizing JavaScript files within our Cypress testing is a common practice. Within the commands.js file, I have developed a custom command: Cypress.Commands.add('selectDropdown', (dropdown) => { cy.get('#' + dropdown).click(); } ...

Incorporating typings for bootstrap-table while compiling TypeScript in an ASP.NET Core application

In my ASP.NET Core 5 app, I have chosen to use TypeScript instead of JavaScript. As part of this decision, I am utilizing some JavaScript libraries in my project and need type definitions for them to compile smoothly. To facilitate this process, I have co ...

Step-by-step guide on building a wrapper child component for a React navigator

When using the Tab.Navigator component, it is important to note that only the Tab.Screen component can be a direct child component. Is there a way in Typescript to convert or cast the Tab.Screen Type to the TabButton function? const App = () => { retur ...

Error: Import statement cannot be used outside a module (@cucumber/cucumber) while using Node.JS, Playwright, and Cucumber framework

I encountered an issue while attempting to compile my Node.js code that is compliant with ECMAScript 6: $ npx cucumber-js --require features/step_definitions/steps.ts --exit import { Before, Given, When, Then } from "@cucumber/cucumber"; ^^^^^^ ...

Encountering an error message stating "Type does not match FunctionComponent<Props>" and "Type is lacking the properties from type 'React Element<any, any>'"

As I work on integrating TypeScript into my code, I keep encountering an error that seems to be related to my Props type. The specific error message I'm facing is: Type '({ volume, onload, isMuted, src, mediaType, ...config }: PropsWithChildren&l ...

Issue: unable to establish a connection to server at localhost port 5000 while using Next.js getServerSideProps function

I am experiencing an issue with connecting to an API on localhost:5000. The API works perfectly when called from Postman or the browser, but it does not work when called inside Next.js getserverside props: mport { useEffect,useState } from "react"; i ...

Issues encountered when attempting to use Angular2 with SystemJs and typescript transpiler

I've encountered an issue with my TypeScript transpiler setup. My @angular component isn't loading, and I'm getting this error message: ZoneAwareError: "Error: core_1.Component is not a function Evaluating http://127.0.0.1:64223/app/app.c ...

The issue arose when attempting to save a nested list of schema types in Typegoose and Mongoose, resulting in a failed Cast to

Encountering this issue: Error: Competition validation failed: results.0: Cast to ObjectId failed for value "{ name: 'David'}" The main model is as follows: class Competition { @prop() compName: string @prop({ ref: () => C ...

Assign a predetermined value to a dropdown list within a FormGroup

I have received 2 sets of data from my API: { "content": [{ "id": 1, "roleName": "admin", }, { "id": 2, "roleName": "user", }, { "id": 3, "roleName": "other", } ], "last": true, "totalEleme ...

How can I ensure that a particular component type passes the typescript check in a react-typescript project?

I'm fairly new to using TypeScript, although I have a lot of experience with React (and prop-types). Recently, I've run into an issue when it comes to typing my components, specifically when another component is passed as a prop. I already have ...

The attribute 'XX' is not recognized within the 'useState' type

I am facing an issue with an API call in my code. Here is a snippet where I receive the response and add it to the state using setInfo: const [info, setInfo] = useState([]) axios.post('/user', { data: 'data' }) .then(response => ...

Retrieve object from nested array based on its id using Angular 6

I have an array of courses, where each course contains an array of segments. In my course-detail component, I have a specific course and I want to retrieve a segment by its ID. For example, let's say I have the following course: { "id": 1, ...

I am looking for guidance on removing the bottom line from the ionic 4 segment indicator. Any advice or tips on

.segment-button-indicator { -ms-flex-item-align: end; align-self: flex-end; width: 100%; height: 2px; background-color: var(--indicator-color); opacity: 1; } I am a beginner in hybrid app development and ...

Modify the request body of a multipart/form-data, then apply the validationPipe

I am attempting to convert a formData request from string to a JSON object using transformation and then validate it with the validationPipe (class-validator). However, I encountered an issue: Maximum call stack size exceeded at cloneObject (E:\p ...