背景:当你接手一些老的前端项目的时候,有时候这个项目同时又js和ts,如何快速将一个老的基于React的项目快速转换为ts风格。前端
import PropTypes from 'prop-types'
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
@connect(
(state, props) => {
const { app, global, info, list, curItem } = state
return {
curApp: list[props.id],
app,
curItem,
total: info.total,
name: global.name,
}
},
dispatch =>
bindActionCreators(
{
save,
update,
remove,
},
dispatch
)
)
export default class Test extends Component {
static propTypes = {
obj: PropTypes.object,
isBool: PropTypes.bool,
str: PropTypes.string,
arr: PropTypes.array,
oneOfType: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
node: PropTypes.node,
oneOf: PropTypes.oneOf(['a', 'b', 'c', 'd']),
func: PropTypes.func,
required: PropTypes.func.isRequired,
}
constructor(props) {
super(props)
this.state = {
isShowModal: false,
modalName: props.report_name || '',
modalType: 'save',
confirmLoading: false,
monitorModalVisible: false,
}
this.aaa = '111'
}
render() {
return <div>hello tscer</div>
}
}
复制代码
import { CompilerOptions, createPrinter, createProgram, EmitHint, transform } from 'typescript'
const program = createProgram([realPath], compileOptions)
const sourceFiles = program
.getSourceFiles()
.filter(s => s.fileName === realPath)
const typeChecker = program.getTypeChecker()
const result = transform(sourceFiles, [
generateGenericPropAndState(typeChecker),
removeImportPropTypes(typeChecker),
removeStaticPropTypes(typeChecker),
])
const printer = createPrinter()
const printed = printer.printNode(
EmitHint.SourceFile,
result.transformed[0],
sourceFiles[0]
)
const res = prettier.format(printed, {
semi: true,
singleQuote: true,
trailingComma: 'es5',
bracketSpacing: true,
parser: 'typescript',
})
复制代码
createProgramnode
program.getSourceFiles()react
transformgit
createPrintergithub
import { isImportDeclaration, isStringLiteral, SourceFile, updateSourceFileNode } from 'typescript'
export const removeImportPropTypes = (typeChecker: TypeChecker) => (
context: TransformationContext
) => (sourceFile: SourceFile) => {
const statements = sourceFile.statements.filter(
s =>
!(
isImportDeclaration(s) &&
isStringLiteral(s.moduleSpecifier) &&
s.moduleSpecifier.text === 'prop-types'
)
)
return updateSourceFileNode(sourceFile, statements)
}
复制代码
这里更多的会将思考过程,代码细节你们能够本身去试试就知道了typescript
一个transform的高阶方程express
sourceFile的结构, 这里就用到我以前说的ast viewwejson
中间的SourceFile便是sourceFile的结构了,选择代码也能够看到代码对应的ast结构redux
这里咱们须要把 import PropTypes from 'prop-types' 删除掉,明细这里对应的是一个叫作 ImportDeclaration 的结构小程序
sourceFile.statements 表明的是每个代码块
filter就按照我以上说的逻辑 去除掉 prop-types
最后返回 updateSourceFileNode, 生成了一个更新后咱们须要新的sourceFile返回
以后的transform功能相似于此的思考过程,因为ts结构vscode有很好的代码提示,以及类型注释,一些ts compiler的api你们根据对应Node的定义应该能够很快的适应
export const removeStaticPropTypes = (typeChecker: TypeChecker) => (
context: TransformationContext
) => (sourceFile: SourceFile) => {
const visitor = (node: Node) => {
if (isClassDeclaration(node) && isReactClassComponent(node, typeChecker)) {
return updateClassDeclaration(
node,
node.decorators,
node.modifiers,
node.name,
node.typeParameters,
createNodeArray(node.heritageClauses),
node.members.filter(m => {
if (
isPropertyDeclaration(m) &&
isStaticMember(m) &&
isPropTypesMember(m)
) {
// static and propTypes
return false
}
if (
isGetAccessorDeclaration(m) &&
isStaticMember(m) &&
isPropTypesMember(m)
) {
// static and propTypes
return false
}
return true
})
)
}
return node
}
return visitEachChild(sourceFile, visitor, context)
}
复制代码