Setting a TypeScript type recursively to allow for changes without affecting tuples

export type DraftObject<T> = {-readonly [P in keyof T]: Draft<T[P]>}
export interface DraftArray<T> extends Array<Draft<T>> {}
export type Draft<T> = T extends any[]
    ? DraftArray<T[number]>
    : T extends ReadonlyArray<any>
        ? DraftArray<T[number]>
    : T extends object ? DraftObject<T> : T


type tup = [number, number, number, number]

const T: Draft<tup> = [1, 2, 3, 4]
const U: tup = [1, 2, 3, 4]

const TT: tup = T
const UU: Draft<tup> = U

The function of DraftObject is to return any type with all its properties marked as not readonly. It works as expected in most cases, however, it incorrectly converts tuple types into arrays. How can I handle tuple types as a special case, and instead of turning them into DraftArrays, mark them as Readonly<>?

Answer №1

According to jcalz, as of TypeScript 3.1, readonly tuples do not exist. To make everything mutable, you can simply use:

export type Draft<T> = {-readonly [P in keyof T]: Draft<T[P]>};

This takes advantage of the mapped tuples and arrays introduced in TypeScript 3.1, along with the pre-existing special case for homomorphic mapped types applied to primitives (where Draft<T> equals T when T is primitive).

Answer №2

If you ever find yourself in a situation where you need to distinguish between tuples and arrays, there's a clever way to do so. Simply take advantage of the fact that tuple types have a defined key with the value of "0" (the string representation, not the number 0), whereas arrays do not possess this key:

type IfTuple<T extends any[], Y=true, N=false> = "0" extends keyof T ? Y : N

type TestTuple = IfTuple<[string, number], "tuple", "array">; // "tuple"
type TestArray = IfTuple<string[], "tuple", "array">; // "array"

By utilizing this logic, you can create a conditional type that behaves differently when dealing with tuples compared to regular arrays.

I hope this explanation proves to be useful. Best of luck with your coding endeavors!

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

The implementation of useState is not functioning properly when used within a parent useState function

I am currently working with a Ticket child class where I set the total amount after changing the number of tickets. The issue I am encountering is that the setNumber function doesn't seem to work properly unless the setTotal function is commented out. ...

Incorporate a JavaScript script into an Angular 9 application

I have been experiencing issues trying to add a script.js file to angular.json and use it in one component. Adding a script tag directly to my HTML file is not the ideal solution. Can someone suggest an alternative approach or point out what I may be missi ...

In order to effectively manage the output of these loaders, it may be necessary to incorporate an extra loader. This can be achieved by using the

I'm currently working with react typescript and trying to implement a time zone picker using a select component. I attempted to utilize the npm package react-timezone-select, but encountered some console errors: index.js:1 ./node_modules/react-timezo ...

"Encountering a 500 error on Chrome and Internet Explorer while trying to sign

I am currently working on an ASP.NET Core application that handles identity management through Azure AD B2C using the ASP.Net Core OpenID Connect. The front end is developed using AngularJS 2 with TypeScript. In my Logout function, the user is redirected t ...

Angular Update Component on Input ChangeEnsuring that the component is automatically

<div class=" card-body"> <div class="row"> <div class=" font-icon-list col-lg-2 col-md-3 col-sm-4 col-xs-6 col-xs-6" routerLinkActive="active" *ngFor="let subject of subjects"> <div class=" fon ...

The output of `.reduce` is a singular object rather than an array containing multiple objects

Building on my custom pipe and service, I have developed a system where an array of language abbreviations is passed to the pipe. The pipe then utilizes functions from the site based on these abbreviations. Here is the parameter being passed to the pipe: p ...

Return to the previous page with different query parameters, not the same one

When it comes to reverting state location back by 1 step in Angular, we can utilize something along the lines of this.location.back();. This method works well unless the system redirects to the same URL but with different query parameters. In such cases, ...

In ReactJS, the way to submit a form using OnChange is by utilizing the

Is there a way to submit a form using Onchange without a button? I need to fire the form but can't insert routes as it's a component for multiple clients. My project is built using react hook forms. const handleChange = (e: any) => { c ...

Using TypeScript to import a Vue 2 component into a Vue 3 application

Recently, I embarked on a new project with Vue CLI and Vite, utilizing Vue version 3.3.4 alongside TypeScript. In the process, I attempted to incorporate the vue-concise-slider into one of my components. You can find it here: https://github.com/warpcgd/vu ...

Angular - Dismiss modal triggered by service, from a header module

Within my Angular application, I have Service S that is responsible for opening Component C MatDialog; I am aiming for C to include a reusable header component called Component H; My goal is for H to feature a button that can close the MatDialog within C; ...

What is the process for assigning a custom React component as the Type for a prop in another component?

Currently, I am working on a customized GenericModal component and would like to include an array of my ModalText components as props in the GenericModal for display purposes. I want to specifically define the type of prop being passed, rather than using s ...

Utilize your custom types within an npm package without the need to release them to @types

I recently came across this npm package (https://www.npmjs.com/package/react-web-notification) and decided to integrate it into my project. To do so, I created an index.d.ts file within the node_modules/@types/react-web-notification folder: import * as Re ...

Retrieving the value of an object using an array of keys

Consider the following object: const obj = { A:{ a1:'vala1', a2:'vala2' }, B:{ b1: 'valb1', b2: 'valb2' }, C:{ c1:{ c11:'valc11' }, c2:'valc2' } } We also have an array: const ...

Mocking a named class-export in TypeScript using Jest

I have a node module that exports several classes, including one called Client, which I utilize to create clients with various APIs as methods. I'm currently attempting to test my module, which has a dependency on this node module, using Jest. Howeve ...

Typescript library available as a private npm dependency

I have developed a Typescript library that I bundle as an npm module. During the development of my frontend application, I easily integrated this library using yarn link. As I set up GitLab CI for other developers to work on the frontend application, I am ...

Challenges encountered while deploying a NextJS project with TypeScript on Vercel

Encountering an error on Vercel during the build deploy process. The error message says: https://i.stack.imgur.com/Wk0Rw.png Oddly, the command pnpm run build works smoothly on my PC. Both it and the linting work fine. Upon inspecting the code, I noticed ...

Issues discovered with using Typescript in Visual Studio 2015

I'm having trouble figuring out the issue. Right now, the typescript file is not appearing correctly in Visual Studio 2015. Take a look at the image linked here: https://i.stack.imgur.com/oXXWD.png ...

Leverage the power of TypeScript with knockout's pureComputed function

I am facing an issue with referencing the this object in a function called problem: const c = { f() { console.log("hi"); }, problem: ko.pureComputed(() => { return this.f(); }), }; [ts] The containing arrow function captures the glob ...

Can you explain the distinction between @types/material-ui and the official @mui/types bundle?

When it comes to npm packages, I came across @types/material-ui and @mui/types. I'm aware that the former is backed by the Definitely Typed community, but what's the reasoning behind its existence when an official types package already exists? D ...

A guide to accessing another component's config.ts file in Angular

After following the steps outlined in this tutorial, I successfully created a reusable modal component. However, when trying to personalize it, I encountered an issue where the modal appeared as an empty box and displayed the error ERROR TypeError: ctx_r1. ...