How does the keyof operator fetch non-enumerable inherited properties from an object literal type?

Take a look at this TypeScript code:

'use strict';

type Value = 1 | 2 ;
type Owner = 'ownerA' | 'ownerB';
type ItemType = 'itemTypeA' | 'itemTypeB';
type Item = {
  type: ItemType;
  owner: Owner;
  value: Value;
};

type AnotherType = {
  [k in keyof Item]: null | {
    [m in keyof Item[k]]: number;
  };
};

const v: AnotherType = {
  type: { itemTypeA: 0, itemTypeB: 1,},
  owner: { ownerA: 0, ownerB: 1,},
  value: null,
};

console.log(v);

When running tsc, an error is thrown:

error TS2322: Type '{ itemTypeA: number; itemTypeB: number; }' is not assignable to type '{ [x: number]: number; toString: number; charAt: number; charCodeAt: number; concat: number; indexOf: number; lastIndexOf: number; localeCompare: …

The issue seems to be with the iteration of [m in keyof Item[k]]: number; as it includes properties like charCodeAt and charAt which are not enumerable or present.

This behavior appears to contradict what the documentation on the 'keyof' type operator states:

The keyof operator takes an object type and produces a string or numeric literal union of its keys. The following type P is the same type as type P = "x" | "y":

type Point = { x: number; y: number };  type P = keyof Point;

According to the documentation, the produced union should only include 'x' and 'y', not non-enumerable values like 'charAt'.

It's possible that the issue lies with the in operator, but in JavaScript, it only iterates through enumerable properties (not certain if this holds true in TypeScript when used as a type operator).

If anyone can provide insight into what's happening here, it would be greatly appreciated.

Answer №1

It is recommended to modify your type definition as follows:

type AnotherType = {
    [K in keyof Item]: null | {
        [M in Item[K]]: number; // <-- no keyof
    };
};

Avoid using the keyof operator within the nested mapped type.

The issue with M in keyof Item[K] arises because Item[K] represents an indexed access type within the Item interface, which can be ItemType, Owner, or Value - already unions of key-like literal types. Writing keyof Item[K] results in evaluating keys-of-keys. It is unnecessary to consider subkeys such as "ownerA" or 1. Direct iteration over Item[K] is more logical, aiming for {[M in Owner]: number}, not {[M in keyof Owner]: number}.

Upon making this adjustment, the updated AnotherType corresponds to

type AnotherType = {
    type: {
        itemTypeA: number;
        itemTypeB: number;
    } | null;
    owner: {
        ownerA: number;
        ownerB: number;
    } | null;
    value: {
        1: number;
        2: number;
    } | null;
}

as intended.

Playground link to code

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

Tips for ensuring that a nested object in an array contains only a single object

My array is structured like this: [ { object1:{ childObj1:[grandChild1,grandChild2], childObj1, childObj1} }, { object2:{ childObj1:[grandChild1,grandChild2], childObj1, childObj1} }, { object3:{ childObj1:[grandChild1,grandChild2 ...

Updating a nested document within an array - Utilizing MongoDB with the Node.js driver

I am struggling to achieve the following task: locate a document with a specific id, then find the corresponding document in the legacy array based on a shortID, and update the sets array of that matched embedded document. For some reason, I can't se ...

"Upon inspection, the TrackerReact Container shows that the user's profile.avatar is set, yet the console is indicating that

Within my app, I designed a TrackerReact container named ProfileSettingsContainer. This container retrieves the user data with Meteor.user() and passes it to a function called user(), then sends this information to the ProfileSettings component. The main o ...

Obtaining Input Field Value in Angular Using Code

How can I pass input values to a function in order to trigger an alert? Check out the HTML code below: <div class="container p-5 "> <input #titleInput *ngIf="isClicked" type="text" class="col-4"><br& ...

Socket.io connects two clients together in a room

Currently, I am working on integrating private messaging functionality into an app I am developing using express 3 and socket.io. Upon a client connection, a room is automatically created and joined based on the client's user id. This feature serves ...

Is it better to import and use useState and useEffect, or is it acceptable to utilize React.useState and React.useEffect instead?

When I'm implementing hooks for state, effect, context, etc, this is my usual approach: import React, { useState, useEffect, useContext } from 'react'; However, I recently discovered that the following also works perfectly fine: import Re ...

Is it possible for JavaScript to be cached when it is located within the body tag of an HTML document?

Currently, I am exploring the topic of How to optimize HTML rendering speed, and came across the idea that scripts in the HEAD tag can be cached. I'm curious, is it possible to cache JavaScript in the BODY tag? If not, I wonder why YUI suggests placi ...

When employing UI-Router, custom directives may not function properly within nested views

I was developing an angular application using phonegap, ionic, and angular. I had created a custom directive that registered an event listener for the element to activate iScroll upon loading. Initially, the directive worked perfectly when all the views we ...

Tips on editing a file exclusively when a specific requirement is fulfilled

Looking for a way to implement a put method within an Express API that allows users to update a document conditionally? Consider this scenario: you have an Instance document with an attribute called executed, which is set to true if the instance has been e ...

What are the steps to connecting incoming data to an Angular view utilizing a reactive form?

Hello, I am currently fetching data from an API and have successfully displayed the teacher values. However, I am unsure of how to utilize the incoming array values for "COURSES" in my Angular view. This is the response from the REST API: { "courses ...

Executing npm run build index.html results in a blank page being generated without any error messages or warnings

After building my react app with npm run build, I encountered a problem where clicking on index.html resulted in a blank page opening in the web browser. I explored several solutions to address this issue but none seemed to work. Some of the strategies I ...

Is there a way for me to configure my website so that when a link is clicked, my PDF file will automatically open in Adobe

I've been facing an issue where I need my users to access a specific PDF file from a link on my website. Currently, the PDF opens in a separate tab next to my site, but ideally, I would like it to be forced to open in Adobe Reader directly. Is this ac ...

Tips for using the .innerHTML method to reference multiple indexes

How can I set the .innerHTML for multiple indexes of an array? I currently have an array let poles = Array.prototype.slice.call(document.querySelectorAll(".pole")); This array contains 9 empty divs, such as : <div class="pole" id="1"></div> ...

When trying to set the state in the OnMouseOver event, an error is thrown: TypeError - React is

Despite encountering numerous posts discussing this issue, I am struggling to resolve it in my particular scenario. I have a collection of items that I am attempting to apply color changes to (the div's) when they are hovered over. The coloring only ...

Dynamically modifying the styling of elements within an iframe

In my current project, I encountered a challenge with changing the background color to black and the body text color to white within an iframe. Additionally, all elements that are originally styled with black in an external stylesheet also need to be chang ...

Styling a modal popup using session storage in CSS

I recently created a modal popup using CSS by following a helpful tutorial that can be found at this link: Now, I am curious about how to store the value entered in a textbox as session data. I came across some code in another tutorial that demonstrated h ...

Guide to verify the user selection within a select form

Here is a form with a select field: <form method="post" name="posting_txt" onSubmit="return blank_post_check();" id="post_txt"> <select style="background: transparent; border-bottom:5px;" name="subname" class="required"> ...

Bootstrap3 Remote Modal experiencing conflict due to Javascript

Utilizing a bootstrap modal to showcase various tasks with different content but the same format is my current goal. However, I am encountering an issue when attempting to make the textareas editable using JavaScript. The conflict arises when I open and cl ...

Implement the fastifySession Middleware within NestJS by incorporating it into the MiddlewareConsumer within the AppModule

I have a Nestjs application running with Fastify. My goal is to implement the fastifySession middleware using the MiddlewareConsumer in Nestjs. Typically, the configuration looks like this: configure(consumer: MiddlewareConsumer) { consumer .appl ...

Is there a way to set a default value for an Angular service provider?

Imagine an Angular Service that encapsulates the HTTP Client Module. export class HttpWrapperService { private apiKey: string; } Of course, it offers additional features that are not relevant here. Now I'm faced with the task of supplying HttpWr ...