As a front-end Developer , Developing ts Project time , The most tedious work should be the data type and mock data , Because if this part of the work is not done , Business logic is written later , If you do, it's all copy and paste similar repetitive work , It takes a lot of time . The following will introduce an automatic generation ts The type and mock Method of data , Help students get rid of tedious work .
Below we will use an example , Let's understand the basic process of code generation .
TS Basic process of code generation
Let's take the following paragraph ts Code, for example , Let's talk about the basic process of generating it .
export interface TestA {
age: number;
name: string;
other?: boolean;
friends: {
sex?: 1 | 2;
},
cats: number[];
}
First step : Select data source
Let's think about a question first , Write the above code interface What information is needed to generate ?
Through analysis , We first need to know how many properties it has , Then you need to know which attributes are necessary , In addition, you need to know the type of each attribute 、 Enumeration and other information . There is a data format that can perfectly provide us with the data we need , It is JSON Schema.
Students who have contacted the back end should have known JSON Schema, It's right JSON Description of the data , for instance , We defined the following JSON structure :
{
"age": 1,
"name": " test ",
"friends": {
"sex": 1
},
"cats": [
1,
2,
3
],
"other": true
}
Let's verbally describe this json: It has age、name、friends、cats、other5 Attributes ,age The type of property is number,name The type of property is string,cats The type of property is number Composed of arry,friends Property is a object, It has one sex attribute , The type is number ,other The type of property is boolean.
use JSON Schema Is described as follows :
{
"type": "object",
"properties": {
"age": {
"type": "number"
},
"name": {
"type": "string"
},
"cats": {
"type": "array",
"items": {
"type": "number"
}
},
"friends": {
"type": "object",
"properties": {
"sex": {
"type": "number"
},
"required": [
"e"
]
}
},
"other": {
"type": "boolean",
},
"required": [
"a",
"b"
]
}
}
It can be seen that JSON Schema Our oral description can be perfectly programmed , This is a simple example ,JSON Schema The ability to describe is much more than that , such as enumeration , The maximum length of an array , The maximum and minimum values of numbers , Is it necessary And so on, our commonly used attributes can accurately describe , Therefore, it is also commonly used in the scenario of user input verification .
The second step : Select the code generation tool
You see the title , I believe most students already know the answer , you 're right , Namely TS AST and TS Compiler API, The latter can generate or modify TS AST, You can also output compiled files . Let's take a look at how to use TS Compiler API Generate an abstract syntax tree and compile it into the code mentioned above .
Corresponding TS Compiler The code is as follows :
factory.createInterfaceDeclaration(
undefined,
[factory.createModifier(ts.SyntaxKind.ExportKeyword)],
factory.createIdentifier("TestA"),
undefined,
undefined,
[
factory.createPropertySignature(
undefined,
factory.createIdentifier("age"),
undefined,
factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword)
),
factory.createPropertySignature(
undefined,
factory.createIdentifier("name"),
undefined,
factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)
),
factory.createPropertySignature(
undefined,
factory.createIdentifier("other"),
factory.createToken(ts.SyntaxKind.QuestionToken),
factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword)
),
factory.createPropertySignature(
undefined,
factory.createIdentifier("friends"),
undefined,
factory.createTypeLiteralNode([factory.createPropertySignature(
undefined,
factory.createIdentifier("sex"),
factory.createToken(ts.SyntaxKind.QuestionToken),
factory.createUnionTypeNode([
factory.createLiteralTypeNode(factory.createNumericLiteral("1")),
factory.createLiteralTypeNode(factory.createNumericLiteral("2"))
])
)])
),
factory.createPropertySignature(
undefined,
factory.createIdentifier("cats"),
undefined,
factory.createArrayTypeNode(factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword))
)
]
)
At first glance, generating this simple type of code is very complex , But take a closer look, if these methods are encapsulated , The code will be much simpler , And there are already some mature third-party libraries , such as ts-morph etc. .
Ts Compiler Api Only English documents , And it's complicated to use , Moreover, we are not sure which function needs to be called to generate different types of code , But we can go TS AST View Inquire about , It can be based on what you enter TS The code generates the corresponding abstract syntax tree and Compiler Code , The above code is TS AST View Provided .
factory.createInterfaceDeclaration
Method will generate a interface node , Generated after , We also need to call a method that will generate interface Print out , Output to string file , The reference codes are as follows :
// ast Transfer code
// Need to add the above factory.createInterfaceDeclaration The generated node is passed in
export const genCode = (node: ts.Node, fileName: string) => {
const printer = ts.createPrinter();
const resultFile = ts.createSourceFile(fileName, '', ts.ScriptTarget.Latest, false, ts.ScriptKind.TS);
const result = printer.printNode(
ts.EmitHint.Unspecified,
node,
resultFile
);
return result;
};
The third step : Beautify the output code
We should be familiar with beautifying the code , I believe we all have Prettier, Necessary tools for each front-end project , It can not only directly format the file we are writing , You can also format the string code we passed in manually , Don't talk much , Code up :
import * as prettier from 'prettier';
// default prettier To configure
const defaultPrettierOptions = {
singleQuote: true,
trailingComma: 'all',
printWidth: 120,
tabWidth: 2,
proseWrap: 'always',
endOfLine: 'lf',
bracketSpacing: false,
arrowFunctionParentheses: 'avoid',
overrides: [
{
files: '.prettierrc',
options: {
parser: 'json',
},
},
{
files: 'document.ejs',
options: {
parser: 'html',
},
},
],
};
// Format beautification file
type prettierFileType = (content:string) => [string, boolean];
export const prettierFile: prettierFileType = (content:string) => {
let result = content;
let hasError = false;
try {
result = prettier.format(content, {
parser: 'typescript',
...defaultPrettierOptions
});
}
catch (error) {
hasError = true;
}
return [result, hasError];
};
Step four : Write the generated code to our file
This step is relatively simple , Directly yes node Provided fs Api Generate a file , The code is as follows :
// Create directory
export const mkdir = (dir:string) => {
if (!fs.existsSync(dir)) {
mkdir(path.dirname(dir));
fs.mkdirSync(dir);
}
};
// Writing documents
export const writeFile = (folderPath:string, fileName:string, content:string) => {
const filePath = path.join(folderPath, fileName);
mkdir(path.dirname(filePath));
const [prettierContent, hasError] = prettierFile(content);
fs.writeFileSync(filePath, prettierContent, {
encoding: 'utf8',
});
return hasError;
};
Front and rear end coordination
The above process still lacks an important step : data source JSON Schema Who provides ?
This requires collaboration between the front and rear ends , At present, the back-end has a very mature generation JSON Schema Tools for , such as Swagger,YAPI etc. .
Access Swagger All back-end system projects can provide... To the front-end swagger.json file , The contents of the file include the detailed data of all interfaces , Include JSON Schema data .
YAPI and Swagger Different , It is API Centralized management platform , Managed on it api We can get all the information through the interface it provides api Detailed data , and swagger.json The content provided is similar , and YAPI The platform supports importing or generating swagger.json.
If there is an interface management platform and relevant specifications are formulated , The efficiency of front and back-end cooperation will be improved a lot , Reduce communication costs , Moreover, the front-end can also do some work related to engineering efficiency based on the management platform .
Overcome the difficulties
The above steps are just a brief introduction to generation ts An idea of type code , There are still some difficulties to be solved under this idea , such as :
- In actual development, we need comments , but TS Compiler API Cannot generate comments : We can solve this problem by re coding string After generation, it is solved by manually inserting notes in the corresponding places .
- The type of actual business can be very complex , The nesting level is deep : This problem can be solved by recursive function .
- Generated type code , If API There are changes , What to do , Or new API To be placed in a file with the original generated , How to deal with this situation ?TS ComPiler API Can read the source file , Even existing files can be read , We can read the source file and then use Compiler API Modify its abstract syntax tree to realize the function of modifying or adding types .
- The coordination of front and rear ends : This needs to find leader It's solved .
summary
After the four steps mentioned above , We learned the basic process of generating code , And the implementation scheme of each step is not fixed , You can choose :
- On the issue of data source selection , We have nothing but JSON Schema You can also choose the original json Data as a data source , It's just that the generated type is not so accurate , Recommend a good website here :JSON2TS.
- We can also use some common template engines to generate code generation tools , such as Nunjucks,EJS etc. , They can not only generate HTML, It's fine too Generate files in any format , And can return the generated string .
- Code beautification is still recommended prettier.
- For the front end , At present, the best way to output files is Node 了 .
This paper only provides an engineering generation method TS type 、Mock Data and other simple and reproducible code , After implementation, it can reduce some labor-intensive Work content of , Let's focus more on business logic development .