Contrasts between { [P in keyof any]: number } and { [P in string | number | symbol]: number }

As a newcomer to TypeScript, I've noticed a discrepancy between keyof any and string | number | symbol in MappedType. However, I'm unclear on the exact distinction between these two syntaxes.

type T = keyof any; 
//string | number | symbol
type T1 = { [P in keyof any]: number };   
//{[x: string]: number}
type T2 = { [P in string | number | symbol]: number }
//{ [x: string]: number; [x: number]: number; [x: symbol]: number; }

A big thank you to everyone for your assistance!

I'm hopeful that some experts can shed light on this question for me.

Answer №1

When creating a mapped type using the syntax {[K in keyof T]: ⋯}, where in keyof is included, TypeScript interprets it as a homomorphic mapped type (refer to What does "homomorphic mapped type" mean?) and applies specific operations based on the type in T. Typically, this involves maintaining the optional/readonly modifiers from the properties of T in the resulting mapped type.

In contrast, if the mapped type resembles {[K in KK]: ⋯} where KK is any keylike type not starting with keyof, TypeScript cannot determine the object type T associated with the keys in KK, leading it to map over the keys in KK independently of T.

This behavior is well-documented, especially in cases where T is a generic type parameter instantiated with an object type. When T is a generic type parameter instantiated with an array/tuple type, or with a primitive type, the homomorphic mapping behaves differently compared to non-homomorphic mapping.


In your scenario, where the type T is defined as any, it represents a unique case. TypeScript treats {[K in keyof any]: ⋯} as a homomorphic mapped type across any, resulting in {[k: string]: ⋯} following the implementation outlined in microsoft/TypeScript#19185, which corresponds to your T1 type.

This interpretation was implemented prior to numeric/symbol keys in keyof and mapped types as realized in microsoft/TypeScript#23592, and considerably ahead of symbol or union index signatures as introduced in microsoft/TypeScript#44512. Consequently, the behavior of homomorphic and non-homomorphic mapped types has slightly diverged for keyof any since then.


Perhaps one could submit a feature request to rectify this inconsistency, although it appears to be a rare scenario that few encounter or find problematic. Neither behavior is outright incorrect, and the discrepancy is just among the various inconsistencies in TypeScript, thus differing behaviors do not signify a bug (e.g., varying behavior is not necessarily a bug).

If you truly intended to obtain the version containing three index signatures and did not intend for the homomorphic mapping, you can sever the link by introducing an alias for keyof any without using in keyof. One way to accomplish this is by employing simple parentheses:

type T3 = { [P in (keyof any)]: number };
/* type T3 = {
    [x: string]: number;
    [x: number]: number;
    [x: symbol]: number;
} */

Instead of keyof any, utilizing the built-in PropertyKey type provided by TypeScript is recommended, declared as such within the TypeScript library at

declare type PropertyKey = string | number | symbol;

This approach yields

type T4 = { [P in PropertyKey]: number };
/* type T4 = {
    [x: string]: number;
    [x: number]: number;
    [x: symbol]: number;
} */

The only situation warranting the use of keyof any over PropertyKey is when code needs to function both before and after support for number and symbol keys in mapped types, covering TypeScript versions prior to and post 2.9. However, this circumstance is highly improbable at present. For recent TypeScript versions, opt for PropertyKey instead of keyof any.

Link to playground for code

Answer №2

Expanding on @jcalz's response: Using keyof any might yield a distinct outcome compared to string | number | symbol when the keyofStringsOnly setting is activated. Nonetheless, you likely won't have to worry about this since the feature has been marked as obsolete in version 5.0.

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

Obtain information from Firebase's real-time database

Within my Ionic application, I am utilizing Firebase to access the data of all registered drivers. The structure of my schema is as follows; ehara Driver fjk59KJjkfkjflhghk driverId: 1 location 0: 9.086 ...

Using ion-list with multiple *ngFor loops

I am trying to combine data from two arrays, "subtitles" and "title", into an ion-list so that each ion-item displays a title on top of a subtitle. How can I achieve this? In my .ts file: items = [ 'Email', 'Phone Number', 'Add ...

The Vitest test is not compatible with PrimeVue3 Dialogs and does not function as intended

I am currently working on a project that involves using PrimeVue components, and the time has come to conduct some tests. Below is the code for the test: import { beforeEach, describe, expect, it } from 'vitest' import type { VueWrapper } from & ...

The issue encountered in Cocos Creator 3.8 is the error message "FBInstant games SDK throws an error stating 'FBInstant' name cannot be found.ts(2304)"

Encountering the error "Cannot find name 'FBInstant'.ts(2304)" while using FBInstant games SDK in Cocos Creator 3.8. Attempting to resolve by following a guide: The guide states: "Cocos Creator simplifies the process for users: ...

Tips for combining values with Reactive Forms

Is there a way to merge two values into a single label using Reactive Forms without utilizing ngModel binding? <label id="identificationCode" name="identificationCode" formControlName="lb ...

One method of extracting an object from an array using a parameter function is by utilizing the following approach

I am searching for a specific object in an array based on the user-provided ID. var laptops = [{ "name": "Firefox", "age": 30, "id": "ab" }, { "name": "Google", "age": 35, "id": "cd", "date": "00.02.1990" }, { "na ...

Using a template literal with the keyof operator as an interface property

Imagine a scenario where we have a basic interface: interface Schedule { interval: "month" | "day"; price: number; } We can create a template-literal type with TypeScript version 4.4: type PrefixedScheduleKey = `schedule__${keyof S ...

What is the procedure for transferring the inputted data from an HTML file to its corresponding TS file and subsequently to a different component file?

I have created two components, a login and a home-page. I am attempting to capture user input from the login template, pass it to the login component, and then display it on the home-page template using the home-page component. What is the best approach to ...

Resizing svg to accommodate a circle shape

As I work on my vue.js app that involves a plethora of diverse icons, I made the decision to create a small icons builder in node.js. The purpose is to standardize their usage and also "crop" each SVG so it fits perfectly within its parent container by uti ...

Angular 7 - Creating tooltips with multiline text

I've utilized template strings to create a multi-line string. toolTip = ` ${Test} : ${number} ${Test} : ${number} ${Test} : ${number} ${Test} : ${number} ${Test} : ${number}}`; The issue I'm facing is that w ...

Troubleshooting the issue with the React Storybook Checkbox change handler functionality

I decided to create a checkbox component using React, Typescript, Storybook, and Styled-Components by following this informative tutorial: building-a-checkbox-component-with-react-and-styled-components. I had to make some adjustments to the code because I ...

A common method for incorporating personalized react-scripts into create-react-app

After creating a project using create-react-app in TypeScript, I am looking to integrate custom react-scripts without ejecting. What is the most effective approach to achieve this? ...

Various types of generics within an object

Is there a way to achieve different types for the nested K type within a type like MyType? Here's an example: type Config<K> = { value: K; onUpdate: (value: K) => void; } type MyType<F extends string> = { [K in F]: <V>() =& ...

Transferring an array of data across different screens within an Ionic 2 application

I am a newcomer to Ionic 2 and I am encountering difficulties when it comes to passing data between pages. Within my Home.ts file, there exists a global array containing certain numbers that have been calculated. My intention is to transfer this array to m ...

Tips for fixing the TS2345 compilation error when working with React

Attempting to implement the setState method in React has resulted in a compile error. Any solutions to this issue would be greatly appreciated. Frontend: react/typescript articleApi.tsx import axios from 'axios'; import {Article} from '../ ...

What is the best way to retrieve the URL query parameters in a Node.js environment?

How can I retrieve URL query parameters in Node.js using TypeScript? Below is my attempted code: /** * My Server app */ import * as Http from "http"; import * as url from "url"; import { HttpServer } from "./HttpServer"; import { TaxCalculator } from ". ...

What is the best way to navigate through this array within my nextjs/typescript/fetch application?

Having trouble finding a way to efficiently search through the CustomersList array. Any help would be greatly appreciated. Here's what happens after fetching the data: const data = await res.json(); return { props: { CustomersList: data, ...

Can you explain the distinction between App: React.FunctionComponent and App = (): React.FunctionComponent()?

Currently exploring the depths of typescript. Can someone clarify the distinction between these two code snippets: const App: React.FunctionComponent<CustomProps> = (props: CustomProps) => { return <div>Hello World!</div>; }; and: ...

Perfroming unit testing on base class using Jasmine and Angular framework

I have a common base class that I include in every grid component. Currently, I have the specifications for the grid component, but I want to create separate specifications for the base class in its own spec file. The goal is to eliminate redundant code ...

Confirm that the string is in the correct JavaScript Date format

I'm encountering an issue with validating the specified string obtained from the new Date() Object. "2020-10-06T14:23:43.964Z". I anticipate receiving either this particular input format or a new Date(). My aim is to create something that ca ...