前文说过,types已经集成到@babel/core里,当然也可以单独安装:
npm i -D @babel/types
概述
@babel/types
的用途主要有3种:
类型集合
当你在ts
中使用babel
时,types
可以为你提供全部节点对应的类型。
let n1: types.Identifier
let n2: types.ExpressionStatement
类型判断
每一种节点类型,都有对应的类型判断方法:
if(types.isIdentifier(n1)) {
// ...
}
if(types.isExpressionStatement(n2)) {
// ...
}
每个类型判断方法,都实现了类型保护,顺道聊一下
TypeScript 类型保护。
先定义一个泛型的类型保护函数:
type IsType<T> = (target: any) => target is T
然后实现一下string
类型保护:
const isString: IsType<string> = (target): target is string => {
return typeof target === 'string'
}
if(isString(abc)) {
// 当此处调用abc时,vscode会按照string类型给予足够提示
abc.slice
}
当然,原生值类型的类型判断比较简单,上面的代码和
if(typeof abc === 'string') {
// ...
}
效果一样。下面对自定义复杂类型做一下类型保护:
type TComplex = {
name: string
age: number
}
const isComplex: IsType<TComplex> = (target): target is TComplex => {
return (
target
&& typeof target.name === 'string'
&& typeof target.age === 'number'
&& !isNaN(target.age)
)
}
至于isComplex
内部如何实现,完全看场景和需求。这一段的关键是:通过类型保护实现的判断,在判断的内部,完全按照该变量类型结构进行提示,开发体验非常棒。
创建节点
每一种节点类型,都有对应的创建方法:
const id = types.identifier('abc')
const str = types.stringLiteral('Hello World')
const num = types.numericLiteral(10e3)
实践
先写个log
方法
import * as types from '@babel/types'
import gen from '@babel/generator'
const log = (node: types.Node) => {
console.log(gen(node).code)
}
创建值类型
log(types.stringLiteral('string'))
log(types.numericLiteral(10e4))
log(types.booleanLiteral(0.5 > Math.random()))
log(types.regExpLiteral('\\.jsx?$', 'g'))
% ts-node gen.ts
"string"
100000
false
/\.jsx?$/g
创建Array
log(
types.arrayExpression([
types.stringLiteral('string'),
types.numericLiteral(10e4),
types.booleanLiteral(0.5 > Math.random()),
types.regExpLiteral('\\.jsx?$', 'g')
])
)
% ts-node gen.ts
["string", 100000, false, /\.jsx?$/g]
创建Object
log(
types.objectExpression([
types.objectProperty(
types.identifier('a'),
types.nullLiteral()
),
types.objectProperty(
// 字符串类型 key
types.stringLiteral('*'),
types.arrayExpression([]),
),
types.objectProperty(
types.identifier('id'),
types.identifier('id'),
false,
// shorthand 对 { id: id } 简写为 { id }
true
),
types.objectProperty(
types.memberExpression(
types.identifier('props'),
types.identifier('class')
),
types.booleanLiteral(true),
// 计算值 key
true
)
])
)
% ts-node gen.ts
{
a: null,
"*": [],
id,
[props.class]: true
}
创建具名 function
log(
types.functionDeclaration(
types.identifier('foo'),
[types.identifier('arg1')],
types.blockStatement([
types.expressionStatement(
types.callExpression(
types.identifier('console.log'),
[types.identifier('arg1')]
)
)
])
)
)
% ts-node gen.ts
function foo(arg1) {
console.log(arg1);
}
创建箭头函数
log(
// 无实体代码块
types.arrowFunctionExpression(
[types.identifier('arg1')],
types.callExpression(
types.identifier('console.log'),
[types.identifier('arg1')]
)
)
)
% ts-node gen.ts
arg1 => console.log(arg1)
log(
// 有实体代码块
types.arrowFunctionExpression(
[types.identifier('arg1')],
types.blockStatement([
types.expressionStatement(
types.callExpression(
types.identifier('console.log'),
[types.identifier('arg1')]
)
)
])
)
)
% ts-node gen.ts
arg1 => {
console.log(arg1);
}
JSX绑定值
log(
types.jsxExpressionContainer(types.identifier('props.name'))
)
% ts-node gen.ts
{props.name}
JSX节点
log(
types.jsxElement(
types.jsxOpeningElement(types.jsxIdentifier('Text'), []),
types.jsxClosingElement(types.jsxIdentifier('Text')),
[types.jsxExpressionContainer(types.identifier('props.name'))]
)
)
% ts-node gen.ts
<Text>{props.name}</Text>
JSXFragment
log(
types.jsxFragment(
types.jsxOpeningFragment(),
types.jsxClosingFragment(),
[
types.jsxElement(
types.jsxOpeningElement(types.jsxIdentifier('Text'), []),
types.jsxClosingElement(types.jsxIdentifier('Text')),
[types.jsxExpressionContainer(types.identifier('props.name'))]
),
types.jsxElement(
types.jsxOpeningElement(types.jsxIdentifier('Text'), []),
types.jsxClosingElement(types.jsxIdentifier('Text')),
[types.jsxExpressionContainer(types.identifier('props.age'))]
)
]
)
)
% ts-node gen.ts
<><Text>{props.name}</Text><Text>{props.age}</Text></>
综合应用:生成React函数式组件
log(
types.program([
types.importDeclaration(
[types.importDefaultSpecifier(types.identifier('React'))],
types.stringLiteral('react')
),
types.exportDefaultDeclaration(
types.arrowFunctionExpression(
[types.identifier('props')],
types.jsxElement(
types.jsxOpeningElement(types.jsxIdentifier('Component'), [
types.jsxAttribute(
types.jsxIdentifier('onClick'),
types.jSXExpressionContainer(
types.identifier('handleClick')
)
)
]),
types.jsxClosingElement(types.jsxIdentifier('Component')),
[
types.jsxElement(
types.jsxOpeningElement(types.jsxIdentifier('Image'), [
types.jsxAttribute(
types.jsxIdentifier('src'),
types.stringLiteral('https://image1.suning.cn/uimg/cms/img/159642507148437980.png')
)
]),
types.jsxClosingElement(types.jsxIdentifier('Image')),
[],
true
)
],
false
)
)
)
])
)
% ts-node gen.ts
import React from "react";
export default (props => <Component onClick={handleClick}><Image src="https://img.wangzhan5u.com/images/5/@babebcdigegxjot.jpg"></Image></Component>);
主要是经验总结的流水账,多用多试就对了。
以上。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!