Describe the TypeScript type for an object with constant keys

My query resembles the one found in this Typescript interface definition question, but has a slight variation.

I am beginning with an object where the keys are constants:

const KEYS = {
  KEY1: 'hello',
  KEY2: 'world'
} as const;

However, instead of strings, I am using objects as the values. So, I am trying to determine the type of the object within each key. (All object types are the same.) For instance, I would like something along these lines:

const KEYS : {const: string} {
  KEY1: 'hello',
  KEY2: 'world'
} as const;

Is there a way to achieve this? I keep encountering ts2353 error due to the improper appearance of the const keyword. Ideally, I am looking for a one-line solution (i.e., what should replace const: string to make it work) since I have nearly 200 keys and rewriting each const individually as a type is not preferable.

As per jcalz's suggestion, it seems like I need something akin to an "index signature"? I have experimented with various types but have not been able to find a working solution, so I am unsure about my approach.

Answer №1

It seems like you are in need of an index signature as you may not be aware of all the property names of a type in advance, but you do know the structure of the values associated with those properties. Instead of using {const: string}, consider utilizing {[k: string]: string}, which defines that every property with the key k will have a value of type string. This can also be represented as Record<string, string> by leveraging the Record utility type.

Given your use of a const assertion, it indicates that you prefer to ensure the compiler retains knowledge of the known keys KEY1 and KEY2, as well as the literal types "hello" and "world". In this scenario, instead of defining the index signature explicitly:

const KEYS: { [k: string]: string } = {
  KEY1: 'hello',
  KEY2: 'world'
} as const;

You should simply verify that KEYS adheres to the defined index signature without altering its inferred type. This can be achieved using the satisfies operator:

const KEYS = {
  KEY1: 'hello',
  KEY2: 'world'
} as const satisfies { [k: string]: string };

This approach allows you to maintain the original type of

KEYS</code while ensuring type safety by alerting you to any incorrect property values:</p>
<pre><code>const KEYS = {
  KEY1: 'hello',
  KEY2: 123 // error!
  //~~ <-- Type 'number' is not assignable to type 'string'.
} as const satisfies { [k: string]: string };

Check out the code on Playground for further exploration

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

What steps do administrators (coaches) need to take in order to generate a new user (athlete) using Firebase Cloud Functions?

I am currently developing a web application designed for coaches and athletes. The main functionality I am working on is allowing coaches to add athletes to the platform. Once added, these athletes should receive an email containing a login link, and their ...

angular 2: how to reset select list values after submission

Issue I am encountering a problem where I am not utilizing a form, but rather using the Model values to populate a select list. Upon clicking the submit button, an API is called with the selected model value. However, after the submission, the select list ...

The side menu fails to appear when pressed

When using the push method, I am unable to see the side menu. However, it works fine with the setRoot navigation. How can I resolve this issue and display the side menu when using the push method? dashboard.html <ion-col col-9> <ion-searchbar ...

What is the best way to bring in local modules within the browser environment using Playwright?

Let me illustrate what I am attempting to achieve: ../src/Foo/Bar.ts represents a local TypeScript file This particular file contains code that is designed to function within a browser environment (it utilizes WebSockets), and therefore needs to be execu ...

Issue with Angular 2 pipe causing unexpected undefined result

Here is a JSON format that I am working with: [{ "id": 9156, "slug": "chicken-seekh-wrap", "type": "dish", "title": "Chicken Seekh Wrap", "cuisine_type": [2140] }, { "id": 9150, "slug": "green-salad", "type": "dish", "title": "Green Sala ...

Angular 7 error: Form control with name property does not have a valid value accessor

Currently, I am utilizing angular 7 and have a parent and child component set up as demonstrated in the Stackblitz link provided below. Strangely enough, when I assign the formControlName from the child component using "id", everything functions flawlessly ...

Resolving the problem of <Link> error in React with Typescript using react-router-dom

Currently, I am facing an issue with the 'react-router-dom' library. This is my first experience using React with Typescript; Everything was functioning properly until I introduced the from 'react-router-dom', which caused the entire ...

Testing the React context value with React testing library- accessing the context value before the render() function is executed

In my code, there is a ModalProvider that contains an internal state managed by useState to control the visibility of the modal. I'm facing a dilemma as I prefer not to pass a value directly into the provider. While the functionality works as expecte ...

Initiate a function once the innerHTML content in Angular has been completely loaded

I'm curious to know if it's possible in Angular to receive a notification when the Inner HTML has finished loading. I have a web application that retrieves an SVG image from a server and I need to display it as innerHTML in order to interact with ...

Change a TypeScript alias within the @types namespace

While using Typescript 3, I encountered a situation where I needed to modify a type alias from the @types/json-schema definition provided by DefinitelyTyped. The issue arose when I wanted to incorporate a custom schema type into my code. Since this custom ...

Using TypeScript to specify the return type of a non-mutating extension function from an external module

Imagine utilizing an external package named "foo". This package's primary export is an object containing an .extend() method that enables functionality addition by generating a derived object (while leaving the original untouched). The process typical ...

Step-by-step guide for importing a JSON file in React typescript using Template literal

I am facing an error while using a Template literal in React TypeScript to import a JSON file. export interface IData { BASE_PRICE: number; TIER: string; LIST_PRICE_MIN: number; LIST_PRICE_MAX: number; DISCOUNT_PART_NUM: Discout; } type Discoun ...

Determining the appropriate generic type in Typescript

In my code, there is a method designed to extend an existing key-value map with objects of the same type. This can be useful when working with database query results. export function extendWith< T extends { id: string | number }, O = | (T[" ...

"Trouble with Typescript's 'keyof' not recognizing 'any' as a constraint

These are the current definitions I have on hand: interface Action<T extends string, P> { type: T; payload: P; } type ActionDefinitions = { setNumber: number; setString: string; } type ActionCreator<A extends keyof ActionDefinitions> ...

`Why are some options missing from the "New Item" feature in Visual Studio?`

Recently, I started a Cordova project using Visual Studio 2015. To my surprise, when I attempt to add a new item by right-clicking, I am presented with only a limited number of options. For example, I wanted to add a "TypeScript json config file" (known as ...

Oops! The API request was denied with error code 401 - Unauthorized in React

I have been working on incorporating an API into my front-end project using React/Typescript. The documentation for the API specifies that authorization requires a key named token with a corresponding value, which should be included in the header. To stor ...

In Angular Google Maps, here's a step-by-step guide on how to zoom in

I am currently utilizing agm/core to showcase the coordinates of a map. Here is the code snippet I am using: <agm-map [latitude]="10.3207886" [longitude]="123.90250049999997"> <agm-marker [latitude]="10.3207886 [longitude]="123.90250049999997 ...

Collapsible list in Angular2 sidenav: ensuring only one sublist remains open

Presenting a functional sidenav demo with Angular 2, TypeScript, and Material Design components. The sidenav features a UL, with the Sites and Users anchors expanding to display their own sub-list. Check out the Plunker here Here is the HTML code for the ...

Experiencing issues while trying to render a component with dynamic content in Next.js

Currently, I am facing an issue while trying to display Leaflet maps in Next.js with Typescript. I came across the suggestion to disable server-side rendering (ssr) to prevent the 'window not defined' error. However, when implementing the followi ...

Encountering "No overload matches this call" error in Typescript while working with fetched data and material-ui

Before attempting to create a dropdown menu with an array retrieved using useSWR, I first practiced creating one with a hardcoded array. I used this for the initial practice: https://codesandbox.io/s/76k0ft?file=/demo.tsx:1819-2045 Instead of using a hard ...