Transform your TypeScript code with a jscodeshift codemod that removes generic type declarations while preserving the wrapped

I am currently working on developing a codemod that will eliminate all instances of the $ReadOnly<T> generic from a TypeScript codebase, while retaining only T (where T represents an object or union).

This is what I have managed to come up with so far:

module.exports = (fileInfo, api) => {
const j = api.jscodeshift
const source = j(fileInfo.source)

source
.find(j.TSTypeAliasDeclaration)
.find(j.TSTypeReference)
.filter(x => {
    return x.value.typeName.name === '$ReadOnly' && x.value.typeParameters.params[0].type === 'TSTypeLiteral'
})
.replaceWith(nodePath => {
    const members = []
    nodePath.value.typeParameters.params[0].members.forEach(x => {
        members.push(j.tsPropertySignature(x.key, x.typeAnnotation))
    })

    return j.tsTypeLiteral(members)
})

return source
    .toSource()
}

The intention is to convert something like this:

export type MyType = $ReadOnly<{
  someProps: string,
}>

To this:

export type MyType = {
  someProps: string,
}

However, the result includes a duplicate type keyword as shown below:

export type type MyType = {
  someProps: string,
}

Any insights on what could be causing this issue?

Answer №1

One way to approach this is by using a declarative method with the putout code transformer tool (you can experiment with it at putout.cloudcmd.io):

// updater.js
const {replaceWith} = require('putout').operator;

module.exports.report = () => '$ReadOnly generic should be removed';

module.exports.match = () => ({
    'export type __a = __b': ({__b}, path) => {
        return __b.name === '$ReadOnly';
    }
});
    
module.exports.replace = () => ({
    'export type __a = __b': (vars, path) => {
        const typeAnnotationPath = path.get('declaration.typeAnnotation');
        const paramPath = typeAnnotationPath.get('typeParameters.params.0');
        
        replaceWith(typeAnnotationPath, paramPath);
        
        return path;
    },
});

This falls under the category of replacer in the putout plugin.

The aim is to transform input like:

// fixture/update-type.js
export type MyType = $ReadOnly<{
  someProps: string,
}>
    
export type MyType2 = $WriteOnly<{
  someProps: string,
}>
    
export type MyType1 = {
  someProps: string,
}

Into an output similar to:

// fixture/update-type-fix.js
export type MyType = {
  someProps: string,
};
    
export type MyType2 = $WriteOnly<{
  someProps: string,
}>
    
export type MyType1 = {
  someProps: string,
}

Putout provides a straightforward test runner for testing your codemod against predefined fixtures:

// type-updater.spec.js
const test = require('@putout/test')(__dirname, {
     'update-type': require('./type-updater'),
});

test('update-type: report', (t) => {
    t.report('update-type', '$ReadOnly generic should be removed');
});

test('update-type: transform', (t) => {
    t.transform('update-type');
    t.end();
});

To apply this codemod, save it in ~/.putout and execute it on your codebase with:

putout .

Alternatively, store it in a directory like your-project/codemods and run:

putout --rulesdir codemods .

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

What is the best way to customize the functionality of the Done (node-dialog-ok) button in node-red when it is

I have created a custom node and I want to trigger some specific actions when the 'Done' button (with id: node-dialog-ok) in the editor-tray-toolbar is clicked, instead of its default functionality. Is it possible to override the onclick event o ...

Tools for parsing command strings in NodeJS

Currently, I'm utilizing SailsJS for my application. Users will input commands through the front-end using NodeWebkit, which are then sent to the server via sockets. Once received, these commands are parsed in the back-end and a specific service/cont ...

Explore within the <li> element using jQuery

Need assistance on how to search within the li element. The li list consists of employee names in the format [surname,firstname]: Venkata,Anusha Raju,Suma Here is the HTML CODE: <input type="text" id="comboBox" placeholder="Search.." /> < ...

Steps for sending Ajax data to your server in order to make changes to your SharePoint list information

After spending a considerable amount of time working on my DataTable, I've managed to incorporate all the necessary functionalities except for one. Currently, my table retrieves data from a SharePoint list through an AJAX "GET" Request and organizes i ...

Unable to access array in the result of a Node.js Mongoose find populate operation

I have the following code in my backend: ad = await Ad.find({'company': companyId}).populate('creator'); When I console.log(ad), this is what I get: [ { connections: [], status: 1, _id: 6047c711b1f8cf1c98b2227c, title ...

Using Ajax and Session Variables for a Worksafe Filter to selectively hide images

Creating a photography portfolio with some images containing nudity prompts the need to hide them by default until the user chooses to reveal them by clicking a "Toggle Worksafe Mode" button. To prevent "confirm form resubmission" errors when users naviga ...

Tips for incorporating JavaScript code into back4app.com using Objective-C:1. Start by accessing the

Currently, I am trying to retrieve "ServerDate" from back4app.com using PFCloud. Unfortunately, I have encountered the following issue: Invalid function: "getServerDate" (Code: 141, Version: 1.13.0) When I attempted to use the code below: [PFCloud ...

Setting the outcome of an Ajax call as a global variable in JavaScript

I have a method that uses AJAX to request data and returns a JSON string containing Tokens records. I am trying to store this result in a global variable named 'tokens' so I can access it in other functions. After assigning the result to the &ap ...

What techniques do Python and Javascript use to handle resizing of arrays?

What methods do programming languages like JavaScript and Python use to resize arrays compared to Java? For example, when adding an element to a 10-index array, Java typically doubles the size of the array while languages such as JS and Python may utilize ...

Operator in RxJS that maps the elements within an array composed of multiple arrays

disclaimer: I have a creative solution and would like to share it here. While exploring the RxJS documentation for map methods that meet this specific requirement - let's call it mapArray - I haven't been able to find one. of([1, 2, 3]).pipe( ...

Error encountered in Node.js OpenAI wrapper: BadRequestError (400) - The uploaded image must be in PNG format and cannot exceed 4 MB

Attempting to utilize the OpenAI Dall-e 2 to modify one of my images using the official Nodejs SDK. However, encountering an issue: This is the snippet of code: const image = fs.createReadStream(`./dist/lab/${interaction.user.id}.png`) const mask = fs.c ...

The field 'token' is not found in the PropsWithChildren<WithUrqlProps> type but it is mandatory in the type '{ token: string; }'

Encountering an error at (ChangePassword) in the export default withUrqlClient(createUrqlClient)(ChangePassword): The argument of type 'FunctionComponent<{ token: string; }> & { getInitialProps?(context: NextPageContext): { token: string; } | ...

Show a nested array retrieved from JSON in a React component

I need assistance in displaying data from my JSON file, particularly an innested array using map(). The field I want to display as a list is analyzedInstructions, which looks like this: How to prep (from p How to prep /p) Steps: Remove the cauliflower&a ...

When the onclick event is triggered, the return value will execute after the onclient

After my onclientclick event finishes, I am trying to run my onclick event. However, regardless of whether my checkbox is selected or not, the program keeps prompting me to "Please select at least one to delete." Can anyone help me figure out why this is h ...

``Is there a way to retrieve the file path from an input field without having to submit the form

Currently, I am looking for a way to allow the user to select a file and then store the path location in a JavaScript string. After validation, I plan to make an AJAX call to the server using PHP to upload the file without submitting the form directly. Thi ...

The process of utilizing the override feature in the package.json file to make updates to child dependencies

There seems to be a vulnerability in the async package that I want to update to version 3.2.2. Here is the dependency tree if I use npm list async: └─┬ [email protected] └─┬ [email protected] └── [email protected] After referring t ...

IE encounters issues making Ajax calls when transitioning from secure HTTPS requests to insecure HTTP requests

I am currently facing an issue with my ajax CORS request. It is functioning perfectly on all browsers except for Internet Explorer. In IE, the request doesn't even attempt to go through and fails instantly without any error messages appearing in the c ...

Easier JavaScript for numerous HTML elements

I am an aspiring JavaScript learner seeking advice. Currently, I am working on a website that features numerous items with multiple images for each. I am utilizing JQuery to display a larger image when the user hovers over a thumbnail image. My query is ...

Sending an array of dictionary objects to a JavaScript function

I have a situation where I need to pass a large amount of data stored in an NSArray containing NSDictionary objects to a JavaScript function using a webview and the method: - (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script My inquir ...

What strategies can I use to successfully navigate through this component?

I'm looking to display "favorite" items within my favorites component. However, I'm facing a challenge since I can't directly pass the postList component to the favorites component. Essentially, I aim to showcase these favorite items on ano ...