Creating an enum using keys from objects within an array in TypeScript

How can I type a string to be within one of the static IDs in a hardcoded array called storage using const storage : Readonly<{id: string}[]>? The array will remain unchanged during runtime.

I attempted (typeof storage)[number]['id'] but it only returns a string. I also tried satisfies Readonly<{id:string}[]>.

interface HasID {
  id: string
  info?: any
}
const storage : Readonly<HasID[]> = [
 { id: 'foo' },
 { id: 'bar', info: ['baz'] }
]
const storage2 = [
  { id: 'foo' },
  { id: 'bar', info: ['baz'] }
] satisfies Readonly<HasID[]>

let str // aiming to type this as "foo" | "bar"

type StorageID = (typeof storage)[number]['id'] // string
type StorageID2 = (typeof storage2)[number]['id'] // string

Answer №1

Many times, when individuals create array literals or object literals, their main intention is to initialize a mutable variable and anticipate changes in its contents. TypeScript tends to infer these types quite broadly. Therefore, even with the introduction of the satisfies operator, the inferred type may be wider than anticipated:

const storage = [
  { id: 'foo' },
  { id: 'bar', info: ['baz'] }
] satisfies Readonly<HasID[]>;
/*
const storage: ({
    id: string;
    info?: undefined;
} | {
    id: string;
    info: string[];
})[]
*/

The specific literal types of the `id` properties tend to get lost.


In scenarios where there is no plan to modify the content of a literal object or array, it's advisable to utilize the const assertion to prompt TypeScript to derive a more precise type:

const storage = [
  { id: 'foo' },
  { id: 'bar', info: ['baz'] }
] as const satisfies Readonly<HasID[]>
/* 
const storage: readonly [{
    readonly id: "foo";
}, {
    readonly id: "bar";
    readonly info: readonly ["baz"];
}]
*/

This type retains the literal types of the `id` property (along with the arrangement of array elements). Subsequently, utilizing indexed access types becomes feasible as intended:

type StorageID = (typeof storage)[number]['id']
//   ^? type StorageID = "foo" | "bar"

Link to code on 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

Exporting Arrays in Ionic Angular with Typescript is an essential feature

When trying to access an exported component in Typescript, there may be issues with importing the module correctly into another component. An error message is displayed when calling the AddToArray method: Cannot read property 'push' of undefi ...

Using Angular to Apply a Custom Validation Condition on a FormGroup Nested Within Another FormGroup

I am facing an issue with my form validation logic. I have a set of checkboxes that need to be validated only when a specific value is selected from a dropdown. The current validator checks the checkboxes regardless of the dropdown value. Here's the c ...

Is it possible for a service to retrieve a component's template?

I am faced with a scenario where two services (A and B) need to communicate with each other. Service A is required to build a chart based on asynchronous data received from service B, which is used in other areas so it operates independently. I attempted t ...

displaying post data in the URL address bar

During the development of my portal using angular 5, everything was running smoothly in the testing environment. However, due to production requirements, I made some changes to access modifiers from private to public. This modification has caused issues in ...

How is it that in TypeScript, a potential numeric value in an interface can be transformed into an impossible numeric value in a class implementation?

Encountered a surprising behavior from the TypeScript compiler today. Unsure if it's a bug or intentional feature. If it is indeed intentional, I would like to understand the reasoning behind it. The issue arises when declaring an interface method wi ...

Save information on the server and organize it into an array for use in local operations

Currently, I am working on the ShoppingApp using Angular for the front-end and Firebase for the backend. I have defined a model for the category as follows: import { ProductModel } from "./product.model"; export class CategoryModel { public id: number; ...

Exploring Angular 8 Routing Testing within a Service

I am currently in the process of testing an Http Interception service that utilizes routing to redirect to another URL upon encountering an error response. All of my tests are passing smoothly since I am not specifically testing the routing functionality i ...

Typescript: The original type cannot be indexed with a type-mapped type

I'm currently working on a class where I need to define a method that returns an object with keys based on the generic type inferred by the compiler. However, I've encountered an issue with the code snippet below. The compiler is indicating that ...

Convert an enum value to a String representation

I need assistance with converting my enum value to a string format export enum Roles { manager = "manager", user = "user" } console.log(" Roles.manager: ", Roles[Roles.manager]); The following is displayed in the console: Roles.manager: manage ...

`How can I stop typescript from converting dynamic imports to require()?`

Currently, I am in the process of creating a Discord bot using discord.js. Interestingly, discord.js does not seem to be compatible with ESM modules, which has been causing some complications in my project. As a result, I have resorted to utilizing CommonJ ...

Dealing with Endless Loops in React TypeScript: What Happens When State is Set in Multiple Instances of the Same

I'm currently facing an issue where I have two instances of the same component being rendered: <div><Modal title='Login'/></div> <div><Modal title='Join'/></div> Within the component, based on ...

What could be causing the Dynamic Options to fail to load on the material-react tailwind component?

I am facing an issue with a subcategory select menu that is supposed to display options based on the selected value in the category select input. Both inputs are utilizing the Select and Option components from the material-tailwind/react library. I have ex ...

Tips for enforcing strict typing in TypeScript when implementing abstract functions

Consider the following scenario with two classes: abstract class Configuration { abstract setName(name: string); } class MyConfiguration extends Configuration { setName(name) { // set name. } } In this setup, the name parameter in M ...

The vertical scrolling functionality of the MUI DataGrid in Safari may occasionally fail to work

Utilizing the <Box> component from MUI core and the <DataGrid> component from MUIX, along with some other components, I have created a data grid that has the following appearance: https://i.sstatic.net/Gc8sP.png When the number of rows exceed ...

Error encountered in TypeScript when attempting to combine type string, number, or null, but not when combining only string or

What causes the function foo to display an error message Type 'string | number' is not assignable to type 'string'. Type 'number' is not assignable to type 'string'. at the return value; line while the function bar f ...

Angular 2 does not recognize the existence of .then in type void

I have a query regarding Angular2 and I'm struggling with the void function in my code. Can someone help me out? I am new to Angular2 and unsure of what needs to be added in the void function. Check out this image for reference export class PasswordR ...

Joining the Parent Route String with a Variable using Angular Routerlink

How can I incorporate string interpolation or concatenation into the router link below in order to navigate to the parent route and include a variable link? <a routerLink="../account-information/{{item.productId}}"> ...

The field in the constructor is guaranteed to have a value, but when accessed in a method, it may be null in TypeScript

Here is the link to my source code When I try to access api/cateogry/:id, there seems to be an issue with the ControllerBase.ts file. Specifically, in the findById method, the this._service property is showing as null even though it was initialized in the ...

Is it possible to utilize an enum for typing an array variable?

Is there a way to use an enum to define the valid types that an array can contain? I have been unable to find a solution so far, and I am curious if it is feasible. Below is the example code I have tried: interface User { name: string; } interface Ad ...

SystemJS could not locate the root directory for RxJS

There seems to be an issue with SystemJS loading rxjs modules on Windows, as it throws a 404 Not Found error on the rxjs directory. This problem does not occur on OSX, and all modules are up to date. GET http://localhost:8080/node_modules/rxjs/ 404 (Not F ...