0

我目前正在尝试编写一个 codemod,它将$ReadOnly<T>从 TypeScript 代码库中删除所有泛型,仅保留TT作为对象/联合)

到目前为止,这就是我想出的

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()
}

我们的想法是修改如下内容:

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

对此:

export type MyType = {
  someProps: string,
}

不幸的是,这就是我最终的结果,带有重复的type关键字:

export type type MyType = {
  someProps: string,
}

知道这里可能出了什么问题吗?

4

1 回答 1

0

可以使用putout代码转换器以声明性方式编写(您可以在putout.cloudcmd.io中尝试):

// type-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;
    },
});

这是替换类型的putout plugin.

它将改变输入:

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

进入输出:

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

Putout有一个简单的测试运行器,因此您可以codemod使用预定义的夹具测试您的:

// 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();
});

要运行它,codemod请将其保存到~/.putout您的代码库中并在您的代码库上运行:

putout .

或者保存在目录中your-project/codemods并运行:

putout --rulesdir codemods .
于 2021-05-03T21:43:28.870 回答