Startec

Startec

Typescript Code Generation

Mai 24, às 17:52

·

5 min de leitura

·

0 leituras

Do you ever wonder how to generate TypeScript code automatically? Using the TypeScript Compiler API, we can leverage it's factory functions for writing scripts that can generate TypeScript code, based on any...
Typescript Code Generation

Cover image for Typescript Code Generation

Do you ever wonder how to generate TypeScript code automatically?

Using the TypeScript Compiler API, we can leverage it's factory functions for writing scripts that can generate TypeScript code, based on any rules we want!

To get started, create a new project with npm init then install the "typescript" npm package with npm install typescript. Create a file index.mjs with touch index.mjs which will hold our code generation script.

Next, we want to figure out what kind of code we want to generate. For this example, we will generate the following function:

function add(a: number, b: number): number {
 return a + b;
}

Enter fullscreen mode Exit fullscreen mode

This is a very simple example, but the concepts apply to any type of code you want to generate.

Inside index.mjs, import the "typescript" package and start exploring what is available in it via intellisense. For this example, we see that we will need to define a few "identifiers", specifically a, b and add. Those are all "names" and are represented by identifiers inside Abstract Syntax Trees.

We can start by defining each identifier at the top of our file using the factory method called createIdentifier:

const aId = ts.factory.createIdentifier("a");
const bId = ts.factory.createIdentifier("b");
const addId = ts.factory.createIdentifier("add");

Enter fullscreen mode Exit fullscreen mode

We'll also need the number keyword a few times so we can add that right below the others:

const numberKeyword = ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword)

Enter fullscreen mode Exit fullscreen mode

Then we can start creating the function declaration and use intellisense to figure out what needs to be provided:

const addFunc = ts.factory.createFunctionDeclaration(
 /* modifiers */,
 /* asteriskToken */,
 /* name */,
 /* typeParameters */,
 /* parameters */,
 /* type */,
 /* body */
)

Enter fullscreen mode Exit fullscreen mode

We can see that it takes a few slots for different types of AST nodes. We'll need to use a few of them, and the others we can leave blank with an undefined value.

The first two, modifiers and asteriskToken we can leave blank since we don't need them here. The next one name we can use our addId we defined earlier. For typeParameters we can leave blank. For parameters, we'll need to define two, one for each parameter, using the identifiers we already created. For type we can use the numberKeyword we already defined, this represents the return type of the function. Finally, for body we will create a new block node that includes a return statement with a binary expression that adds the two parameters together.

There are a lot of technical terms here - for in-depth details on everything mentioned here, take a look at my new book "The Typescript Compiler API" that explains everything from A-Z for code generation, AST's and more!

Then to print it out, we can use a printer by doing:

function print(nodes) {
 const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
 const resultFile = ts.createSourceFile(
 "temp.ts",
 "",
 ts.ScriptTarget.Latest,
 false,
 ts.ScriptKind.TSX
 );
 console.log(printer.printList(ts.ListFormat.MultiLine, nodes, resultFile));
}
print([addFunc]);

Enter fullscreen mode Exit fullscreen mode

The final script should look like this:

import ts from "typescript";
const aId = ts.factory.createIdentifier("a");
const bId = ts.factory.createIdentifier("b");
const addId = ts.factory.createIdentifier("add");
const numberKeyword = ts.factory.createKeywordTypeNode(
 ts.SyntaxKind.NumberKeyword
);
const addFunc = ts.factory.createFunctionDeclaration(
 undefined,
 undefined,
 addId,
 undefined,
 [
 ts.factory.createParameterDeclaration(
 undefined,
 undefined,
 aId,
 undefined,
 numberKeyword,
 undefined
 ),
 ts.factory.createParameterDeclaration(
 undefined,
 undefined,
 bId,
 undefined,
 numberKeyword,
 undefined
 ),
 ],
 numberKeyword,
 ts.factory.createBlock(
 [
 ts.factory.createReturnStatement(
 ts.factory.createBinaryExpression(
 aId,
 ts.factory.createToken(ts.SyntaxKind.PlusToken),
 bId
 )
 ),
 ],
 true
 )
);
function print(nodes) {
 const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
 const resultFile = ts.createSourceFile(
 "temp.ts",
 "",
 ts.ScriptTarget.Latest,
 false,
 ts.ScriptKind.TSX
 );
 console.log(printer.printList(ts.ListFormat.MultiLine, nodes, resultFile));
}
print([addFunc]);

Enter fullscreen mode Exit fullscreen mode

When we run node index.mjs, we should see the following printed to the console:

function add(a: number, b: number): number {
 return a + b;
}

Enter fullscreen mode Exit fullscreen mode

Congratulations, you just generated your first function! If you enjoyed this exercise and want to learn more about code generation, abstract syntax trees, linters, customer diagnostics in Typescript and more, then feel free to check out my new book that covers all of this in-depth. Cheers!


Continue lendo

DEV

Simplify Your Documentation Workflow with MkDocs: A Markdown-based Alternative to Sphinx
Introduction: Documentation is an essential aspect of software development, enabling developers to communicate effectively with users and fellow developers. Sphinx and MkDocs are two popular documentation...

Hoje, às 08:30

DEV

Is It Burnout or Job Dissatisfaction?
Once suspended, devteam will not be able to comment or publish posts until their suspension is removed. Once unsuspended, devteam will be able to comment and publish posts again. Once...

Hoje, às 07:00

Hacker News

Experiences Won't Make You Happier Than Possessions
You will be happier if you spend your money on experiences rather than possessions… or so says the modern truism, supposedly proven by psychological science. Researchers call it the “experience...

Hoje, às 06:57

DEV

How to print “Hello” in C without using a semicolon?
#include <stdio.h> int main() { if(printf("Hello World\n")){ } switch(printf("Hello World\n")){ } while(!printf("Hello World")){ } return 0; } Enter fullscreen mode Exit fullscreen...

Hoje, às 06:54

DEV

Perfect Number Program in C
For explanation watch video Perfect Number : In mathematics, a perfect number is a positive integer that is equal to the sum of its positive divisors, excluding the number itself. ex : 6 = 1,2,3 < 6...

Hoje, às 06:52

DEV

Left Shift Bitwise Operator in C Programming (Short Trick)
Read next Leveraging Cache to improve Web Performance Jakub Andrzejewski - May 8 How to develop an online code compiler using Java and Docker. Zakaria Maaraki - Apr...

Hoje, às 06:49

DEV

¡Adiós Options API, Hola Script Setup! La no tan nueva forma de programar en Vue 3
script setup proporciona una forma más concisa de utilizar la Composition API en Single File Components (SFCs). En su versión 3, Vue introdujo un nuevo sistema para organizar el código de los componentes...

Hoje, às 06:24

DEV

How to implement subscription model using LemonSqueezy in Next.js (13.4 stable app router)
Table of contents Introduction Getting Started Setup Next.js app User Registration Setup LemonSqueezy account How subscription works Implementing Subscription Creating a checkout Synchronization with...

Hoje, às 06:00

DEV

How to FIND the QUESTIONS that will be in an interview
Trying to figure out what exact areas to study/practice to prep for an upcoming tech interview can be stressful! In order to maximize your chances of success and ensure a strong performance during the...

Hoje, às 04:08

DEV

What you learning about this weekend?
Heyo 👋 What ya learning on this weekend? Whether you're sharpening your JS skills, making PRs to your OSS repo of choice 😉, sprucing up your portfolio, or writing a new post here on DEV, we'd like to hear...

Hoje, às 04:00