eslint手动检测typescript参数类型

最近在做eslint中的typescript参数类型检测,本来想直接用typescript-eslint-parser 检测,但发现项目中有些代码是用mobx注入的,typescript-eslint-parser检测不出来,于是找了些eslint和typescript的资料来看,经过一番实践之后,找到了一些思路。下面简单写一下如何在eslint中手动检测typescript中的参数类型。 首先,需要安装@typescript-eslint/typescript-estree,建议新建一个文件夹后执行,注意下跟typescript的版本兼容性 yarn add -D @typescript-eslint/typescript-estree 编写如下脚本,命名为ts_getnode.tsx,放在前面创建的文件夹下 ###!/usr/bin/env ts-node var fs = require("fs"); const parser = require('@typescript-eslint/typescript-estree'); console.log(process.argv) const filepath = process.argv[2];//前面两个参数分别为ts-node的路径和test1.tsx的路径 const code = fs.readFileSync(filepath).toString(); console.log("文件内容",code); const ast = parser.parse(code, { range: true, loc: true, jsx:true//开启后检测jsx }); // console.log(JSON.stringify(ast)); // console.log(ast); fs.writeFile("output.txt",JSON.stringify(ast),(err:any)=>{ if (err) { return console.error(err); } console.log("数据写入成功!"); }) 3.执行上一步创建的脚本,参数为需要检测的文件路径,如/Users/luojin/Desktop/test_ts/test1.tsx ts-node get_tsnode.tsx /Users/luojin/Desktop/test_ts/test1.tsx 这里,我是用了ts-node来在终端执行,你也可以放在其他任何能执行typescript脚本的环境中执行 4.跑出来的结果(AST)会写在同一个目录下的output.txt文件中,复制出来,粘贴到可以解析json的网站,如https://www.json.cn/就可以看到解析的结果。 以笔者自己写的一段代码测试代码为例: function helloWorld (str:any) { console.log(str) } helloWorld('hello world!') 解析出来是 { "type":"Program", "body":[ { "type":"FunctionDeclaration", "id":{ "type":"Identifier", "name":"helloWorld", "range":[ 9, 19 ], "loc":{ "start":{ "line":1, "column":9 }, "end":{ "line":1, "column":19 } } }, "generator":false, "expression":false, "async":false, "params":[ { "type":"Identifier", "name":"str", "range":[ 21, 28 ], "loc":{ "start":{ "line":1, "column":21 }, "end":{ "line":1, "column":28 } }, "typeAnnotation":{ "type":"TSTypeAnnotation", "loc":{ "start":{ "line":1, "column":24 }, "end":{ "line":1, "column":28 } }, "range":[ 24, 28 ], "typeAnnotation":{ "type":"TSAnyKeyword", "range":[ 25, 28 ], "loc":{ "start":{ "line":1, "column":25 }, "end":{ "line":1, "column":28 } } } } } ], "body":{ "type":"BlockStatement", "body":[ { "type":"ExpressionStatement", "expression":{ "type":"CallExpression", "callee":{ "type":"MemberExpression", "object":{ "type":"Identifier", "name":"console", "range":[ 34, 41 ], "loc":{ "start":{ "line":2, "column":2 }, "end":{ "line":2, "column":9 } } }, "property":{ "type":"Identifier", "name":"log", "range":[ 42, 45 ], "loc":{ "start":{ "line":2, "column":10 }, "end":{ "line":2, "column":13 } } }, "computed":false, "optional":false, "range":[ 34, 45 ], "loc":{ "start":{ "line":2, "column":2 }, "end":{ "line":2, "column":13 } } }, "arguments":[ { "type":"Identifier", "name":"str", "range":[ 46, 49 ], "loc":{ "start":{ "line":2, "column":14 }, "end":{ "line":2, "column":17 } } } ], "optional":false, "range":[ 34, 50 ], "loc":{ "start":{ "line":2, "column":2 }, "end":{ "line":2, "column":18 } } }, "range":[ 34, 50 ], "loc":{ "start":{ "line":2, "column":2 }, "end":{ "line":2, "column":18 } } } ], "range":[ 30, 52 ], "loc":{ "start":{ "line":1, "column":30 }, "end":{ "line":3, "column":1 } } }, "range":[ 0, 52 ], "loc":{ "start":{ "line":1, "column":0 }, "end":{ "line":3, "column":1 } } }, { "type":"ExpressionStatement", "expression":{ "type":"CallExpression", "callee":{ "type":"Identifier", "name":"helloWorld", "range":[ 53, 63 ], "loc":{ "start":{ "line":4, "column":0 }, "end":{ "line":4, "column":10 } } }, "arguments":[ { "type":"Literal", "raw":"'hello world!'", "value":"hello world!", "range":[ 64, 78 ], "loc":{ "start":{ "line":4, "column":11 }, "end":{ "line":4, "column":25 } } } ], "optional":false, "range":[ 53, 79 ], "loc":{ "start":{ "line":4, "column":0 }, "end":{ "line":4, "column":26 } } }, "range":[ 53, 79 ], "loc":{ "start":{ "line":4, "column":0 }, "end":{ "line":4, "column":26 } } } ], "sourceType":"script", "range":[ 0, 79 ], "loc":{ "start":{ "line":1, "column":0 }, "end":{ "line":4, "column":26 } } } 对比用tsc转成javascript后再用esprima解析(只能解析javascript)的结果. esprima网站: https://esprima.org/demo/parse.html# { "type": "Program", "body": [ { "type": "FunctionDeclaration", "id": { "type": "Identifier", "name": "helloWorld" }, "params": [ { "type": "Identifier", "name": "str" } ], "body": { "type": "BlockStatement", "body": [ { "type": "ExpressionStatement", "expression": { "type": "CallExpression", "callee": { "type": "MemberExpression", "computed": false, "object": { "type": "Identifier", "name": "console" }, "property": { "type": "Identifier", "name": "log" } }, "arguments": [ { "type": "Identifier", "name": "str" } ] } } ] }, "generator": false, "expression": false, "async": false }, { "type": "ExpressionStatement", "expression": { "type": "CallExpression", "callee": { "type": "Identifier", "name": "helloWorld" }, "arguments": [ { "type": "Literal", "value": "hello world!", "raw": "'hello world!'" } ] } } ], "sourceType": "script" } 忽略loc和range,可以看到typescript主要是多了typeAnnotation这个字段,里面就包括了参数的类型信息。 在eslint的自定义规则里来拿到这个typeAnnotation进行处理,这个就不详细讲了,可以参考https://www.jianshu.com/p/1c805c52c51d 当前访问节点的所有信息都是从node 中拿到,只是需要注意Identifier才有typeAnnotation 笔者写了一个脚本,检查参数是否有any类型的,如下 module.exports = { meta: { docs: { description: 'disallow any type', category: 'Possible Errors', recommended: true, }, fixable: 'code', schema: [], // no options }, create: function(context) { return { Identifier: function(node) { const { typeAnnotation,type } = node; if (typeAnnotation != undefined) { if (typeAnnotation.typeAnnotation.type == "TSAnyKeyword") { context.report({ node, message: '{{ str }} is any type', data: { str: node.name, }, }); } } }, }; }, };

本文章由javascript技术分享原创和收集

发表评论 (审核通过后显示评论):