When using a typescript type created in typescript 4.4, it functions correctly, however, there may be inconsistencies when using it in typescript versions 4.5

Currently, I am tackling a query from type-challenges.

The task at hand involves implementing a generic MyReadonly2<T, K>, which requires two type arguments: T and K.

K defines the properties of T that should be set to Readonly. In cases where K is absent, all properties are made readonly, much like the normal Readonly behavior. The current solution is functional in v4.4 but experiences issues in v4.5+.

//solution 1
type MyReadonly2<T, K extends keyof T = keyof T> = T & {
  readonly [P in K]: T[P]
}

Replicating the issue:

The solution in v4.7.2 : here


I'm struggling to comprehend why solution 1 fails to work as intended.

Answer №1

An issue was identified in TypeScript where the behavior was initially seen as a bug, which was reported and fixed in versions microsoft/TypeScript#45122 and microsoft/TypeScript#45263 respectively, with the release of TypeScript 4.5.

The question arises on how TypeScript should handle the intersections of object types containing properties with the same key, some being readonly while others are not. The debate is whether the resulting property should be readonly or not. For instance, should

{readonly a: string} & {a: string}
result in {readonly a: string} or {a: string}?

In essence, despite its name, readonly signifies "this is readable," whereas non-readonly indicates "this is readable and writable." In the context of intersections meaning "and,"

{readonly a: string} & {a: string}
would ideally have a property a that is both readable and writable, leading to the conclusion that the final type should be {a: string} without the readonly modifier. This implies that a property should only be marked readonly if it holds that attribute in every member of the intersection where it appears. Intersections cannot introduce the readonly modifier to a property that is not originally defined as readonly.

Prior to TypeScript 4.5, there was an incorrect implementation where a property in the final object became readonly if it held that attribute in any one of the intersecting members. This behavior was rectified in later versions.


This change in behavior in TypeScript 4.5 explains why certain code implementations were impacted. For example, something like T & Readonly<Pick<T, K>> should not be able to add readonly to keys in K as they are also part of keyof T. However,

Omit<T, K> & Readonly<Pick<T, K>>
can include readonly modifiers since K's keys are absent from keyof Omit. You can achieve similar results with Omit<T, K> & Readonly<T> without needing to exclude other keys.

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

Safety in Choosing Typescript with "Name Safety"

I have a working code snippet that I'm currently using: export interface IReq { timestamp: number; }; export interface ITrack extends IReq { id: number; }; const track: Pick<ITrack, 'id'> = { id: 1 } While it's goo ...

What steps can be taken to avoid the widespread application of [(NgModel)] to multiple input fields?

I'm a little puzzled about what to utilize besides [(ngModel)]. As you can see from the code snippet and images below, ngModel binding is applied to all other input fields when I click on the Edit button due to *NgFor. Can anyone offer some recommenda ...

I'm encountering an issue in my node application where it is unable to access the push

I am a beginner in the world of node.js and express. Whenever I try to start my application using the command npm start, I encounter an error message saying Cannot Read property push of undefined from my index.js file. The problematic code snippet looks l ...

How can I determine the data type of an Array element contained within an Interface member?

Is there a way to extract the type of key3 in MyInterface2 and use it in key3Value, similar to key2Value? interface MyInterface { key1: { key2: string } } const key2Value: MyInterface['key1']['key2'] = 'Hi' / ...

React website successfully completes builds and deployments, however upon viewing, it displays as a blank white screen

Hi there, I am a beginner in web development and decided to experiment with building a React site. Everything was working perfectly on my local machine, so I followed a tutorial to host it on GitHub. The deployment process seemed fine without any errors. H ...

In Nextjs13, it is essential to call font loaders and assign them to a constant within the module scope

I'm encountering an issue while trying to integrate Google Font into my Next.js project. In Next.js 12, I successfully used the font link in the head section, but now in Next.js 13, I am facing errors even when attempting to use @next/font/local. I h ...

The concept of contextual typing within Typescript is essential for ensuring proper

Snippet: class A { x: number; } class B extends A { y: number; } var f1: { (y: A): void } | { (y: B): void }; f1 = (y)=>{} // y :any var f2: { (x: number): (y: A) => void } | { (x: number): (y: B) => void }; f2 = ((x) => { return (y ...

Working with Union Types in the state of React's Context API using TypeScript

I'm facing an issue where TypeScript is not recognizing the existence of the property state.recipes when I use the state in another component. This seems to occur when YummlyState is the type of RecipesState. I have a hunch that YummlyState always def ...

Is there a way to implement jquery (or other external libraries) within Typescript?

Currently, I am diving into Typescript to enhance my skills and knowledge. For a project that is being served with Flask and edited in VSCode, I am looking to convert the existing JavaScript code to Typescript. The main reason for this switch is to leverag ...

Troubleshooting a TypeScript Problem with React Context

In my AppContext.tsx file, I have defined the following import React, { useState, createContext } from "react"; import { Iitem } from "../utils/interfaces"; interface AppContext { showModal: boolean; setShowModal: React.Dispatch< ...

The creation of a fresh child instance in Typescript using rest parameters

My goal is to create a parent class that allows children to generate new instances of the same child type. When I specify the number of parameters, everything functions correctly: abstract class AClass { protected sameTypeWithSingle ( x: any ): t ...

Typescript turns a blind eye to improper usage of a passed prop function within React components

My React component is structured like this: const BirthdaySearch: FC<{ onSearch: (year: string, month: string) => void }> = (props) => { const monthInputRef = useRef<HTMLInputElement>(null); const dayInputRef = useRef<HTMLInp ...

What are the steps to utilizing the Global extension in Angular?

While working on my Angular 12 application, I developed the following string extension: declare global { interface String { toNumber(): number | null; } } Object.defineProperty(String.prototype, "toNumber", { value: function(this: stri ...

What is the specific type of event for a change handler in TypeScript?

As a newcomer to TypeScript, I recently crafted a change handling function that accepts the event as a parameter to assign the value, like event.target.value. Currently, I have designated this as any, but I suspect there is a more appropriate type for this ...

Tips for refreshing a component after fetching a new page using the useQuery function

Attempting to retrieve and display data from my custom API using axios and react-query's useQuery. The API incorporates pagination, and I have implemented a table with an option to select the page that displays the current data. Everything functions c ...

Is it possible to modify the parameters of a function by utilizing a MethodDecorator without affecting the "this" value?

Consider a scenario where you need to dynamically modify method arguments using a decorator at runtime. To illustrate this concept, let's simplify it with an example: setting all arguments to "Hello World": export const SillyArguments = (): MethodDec ...

Updating the state of Formik

Currently, I'm knee-deep in a React project that requires a slew of calculations. To manage my forms, I've turned to Formik, and for extra utility functions, I've enlisted the help of lodash. Here's a peek at a snippet of my code: impor ...

Assign the primeng dropdown's value to the model in a reactive form

I am currently encountering an issue while populating a form that contains several PrimeNg dropdowns. To simplify, let's consider an example similar to the ones provided on their website. <form [formGroup]="myFormGroup"> <p-dropdown [optio ...

Navigating through Expo with Router v3 tabs, incorporating stack navigation, search functionality, and showcasing prominent titles

I've been working on designing a navigation header similar to the Apple Contacts app, with a large title and search function, but only for the Home Screen. All other tabs should have their own unique settings, like different titles or hidden navigatio ...

Dealing with reactive form controls using HTML select elements

I am working with a template that looks like this: <form [formGroup]="form"> <mdl-textfield type="text" #userFirstName name="lastName" label="{{'FIRSTNAME' | translate}}" pattern="[A-Z,a-zéè]*" error-msg ...