Access key-value pairs of objects without the use of the keyword "as"

const resources = {
  background: '',
  player: '',
};
const totalResourceCount = Object.keys(resources).length;

type resourceKey = keyof typeof resources;

export class ResourceLoader {
  images: Record<resourceKey, HTMLImageElement>;
  loadedCount = 0;
  onResourcesLoaded: VoidFunction;

  constructor(onLoaded: VoidFunction) {
    this.onResourcesLoaded = onLoaded;
    const imageMap = {} as Record<resourceKey, HTMLImageElement>;

    Object.entries<string>(resources).forEach(([key, source]) => {
      const img = new Image();
      img.onload = this.onLoad;
      img.src = source;
      imageMap[key as resourceKey] = img;
    });

    this.images = imageMap;
  }

  private onLoad = () => {
    this.loadedCount++;
    if (this.loadedCount === totalResourceCount) {
      this.onResourcesLoaded();
    }
  };
}

I am looking for a way to define typed resources with keys limited to the ones specified in another object.

Is there an alternative method to write the constructor without using "as"?

Any suggestions on improving the code that maps {key: source} -> {key: loadedImage} while tracking the number of items already loaded?

Answer №1

In summary, it is recommended to use the as keyword or create an array of keys as a workaround.


The TypeScript standard library's typing for Object.entries(obj) and Object.keys(obj) returns keys as strings instead of keyof typeof obj due to the open nature of object types in TypeScript.

The code snippet provided illustrates this concept by showing how properties can be extended in TypeScript interfaces. The compiler does not have a way to represent types with no extra properties, so you may need to explicitly handle known keys using type assertions or redundant key arrays.


If you want to specify only certain keys to the compiler, you can utilize a type assertion like:

(Object.entries(assets) as [assetKey, string][]).forEach(([key, assetSrc]) => {
  // Code here
});

Alternatively, you can define your own array of known keys like:

(["key1", "key2"] as const).forEach(key => {
  // Code here
});

Both methods serve the purpose of informing the compiler about the specific keys to consider. You can choose between them based on your preference for readability and safety.

Overall, handling these scenarios usually involves some form of type assertion to communicate intentions clearly to the TypeScript compiler.


Hopefully, this explanation provides insights and guidance for dealing with such situations effectively. Best of luck!

Explore more on TypeScript 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

Learn how to generate specific error messages based on the field that caused the failure of the @Column({ unique: true }) Decorator. Error code 23505

Hey there! I'm currently facing an issue while trying to handle Sign Up exceptions in my code. I want to inform the user if their username OR email is already in use. Although using the decorator @Column({ unique: true}) allows me to catch error 23505 ...

How can you merge arrays in Angular based on their unique names?

Is there a way to combine objects within the same array in Angular based on their names? [{ "name":"Navin", "id":"1" }, { "name":"Navin", "mark1":"98" ...

The error message "vimeo/player.js - Unable to access property 'nativeElement' as it is undefined" appeared

I am encountering difficulties integrating vimeo/player.js into my angular-cli application. There isn't a supporting library for Angular 4, so I'm following the steps in the README.md under "Using with a module bundler". I created a vimeo-player ...

Issue when trying to use both the name and value attributes in an input field simultaneously

When the attribute "name" is omitted, the value specified in "value" displays correctly. However, when I include the required "name" attribute to work with [(ngModel)], the "value" attribute stops functioning. Without using the "name" attribute, an error ...

Creating a setup in TypeScript to enable imports between CommonJS and ES modules (for node-fetch and Express)

I'm facing a challenge in trying to integrate two libraries into a single project: fetch-node, an ES module, and Express, which follows the CommonJS format. The issue arises from needing to import fetch-node using: import fetch from 'node-fetch&a ...

Ways to sign up for the activeDate variable in MatCalendar so you can display the month and year labels of the current active date in the

As a newcomer to Angular, I am working on creating a datepicker with a customized header. I have successfully passed a custom header for the mat-calendar component. Reference: https://material.angular.io/components/datepicker/overview#customizing-the-calen ...

Storing information retrieved from the API for use in different modules

Trying to extract data from a WEB API service using Angular 8 has been quite challenging for me. A service I created makes the API call: return this.http.get<UserSession>(uri) .pipe(map((json: UserSession) => this.EntryFormAdapter(json))); Th ...

"Utilizing provideMockStore in NgRx 8 for setting the state of a specific State Slice

I have been working on testing a smart component for my NgRx implementation, and the test setup looks like this: describe( 'Component', () => { let store: MockStore<State>; beforeEach( async( () => { TestBed.configureTesting ...

When using the ionic 3 storage.get function, it may return a null value when accessed outside

In regards to storage, the function is returning a null value outside of the function. Below is the code snippet: username:any; this.storage.get('user').then((value) => { this.username = value; }); console.log(this.username); Ou ...

Assigning a Boolean value of false in JavaScript will result in it being evaluated as true

I'm struggling to understand why my variable continues to evaluate as true and enters the IF block, even after I specifically assign it as false. let isSetToFalse = this.model.hasQ1; console.log('type ', typeof this.model.hasQ1) //I find it ...

How come the Angular8 form status registers as VALID even if the input fields are empty?

The following is the structure of the component: export class SchedulerComponent implements OnInit { schedulerForm : FormGroup; constructor(private fb: FormBuilder, private schedulerReportService: SchedulerReportService) { this. ...

What leads to the inability to utilize environment variables in this TypeScript app built with Vue 3?

Currently, I am developing a single page application utilizing Vue 3 and TypeScript. The main purpose of this app is to interact with an API. All the necessary information including the API's URL and key are stored in the 'src\env.js' f ...

The most efficient method for distributing code between TypeScript, nodejs, and JavaScript

I am looking to create a mono repository that includes the following elements: shared: a collection of TypeScript classes that are universally applicable WebClient: a react web application in JavaScript (which requires utilizing code from the shared folde ...

Nest is having trouble resolving dependencies for this service

Can multiple MongoDB models be injected into one resolver and used? I attempted to accomplish this by first adding the import of SectionSchema and SectionsService to the PostsModule: @Module({ imports: [MongooseModule.forFeature([{name: 'Post&apos ...

Facing a problem with querying interfaces and types in TypeScript

My goal is to pass a variable to an RTK Query API service that uses a typescript interface: const device_id: unique symbol = Symbol(props.id); const { data: device, isFetching, isLoading, } = useGetAssetsByIdQuery(device_id, { pollingInterv ...

Updating Radio Button Value in React Using TypeScript Event Handler

Whenever I try to save different values to the state, I encounter an issue where selecting female results in the male radio button being selected, and vice versa. Do you think it would be better to use a generic 'gender' variable in the state in ...

Having trouble retrieving data from a JSON file within an Angular application when utilizing Angular services

This JSON file contains information about various moods and music playlists. {mood: [ { "id":"1", "text": "Annoyed", "cols": 1, "rows": 2, "color": "lightgree ...

Exploring the functionality of surveyjs in conjunction with react and typescript

Does anyone have any code samples showcasing how to integrate Surveyjs with React and TypeScript? I attempted to import it into my project and utilized the code provided in this resource. https://stackblitz.com/edit/surveyjs-react-stackoverflow45544026 H ...

Angular - Implementing a debounce feature for event handling

Currently, I am utilizing the mouseenter and mouseleave events to control the opening and closing of my sidenav within the app. However, I have encountered issues because when hovering over the container quickly, these events are triggered multiple times ...

How to Retrieve a Global Variable in an Angular Template

Is there a way to access a global variable from an Angular template? let unableToAccess = false; @Component({ selector: 'app-payment', templateUrl: './buy.component.html', styleUrls: ['./buy.component.scss'] }) export ...