Sitemap

Creating Typescript with the Typescript compiler

3 min readDec 3, 2018

The following are things I found out by trial and error about typescript generation, mostly about creating classes

Before you begin

First and foremost don’t forget to import the compiler API.

import * as ts from ‘typescript’;

Its common for a function to make many arguments, even if it doesn’t use them all, use an IDE like Webstorm or VSCode to see what they are.

Creating a constructor

Figuring it out yourself

If you know how to write it in code, but can’t figure out how to compose it with the API you can always reverse engineer it by printing out the JSON of the AST.

function printTypescript(text: string) {
let sourceFile = ts.createSourceFile(
'afilename.ts', text,
ts.ScriptTarget.ES2015,
false,
);
console.log(JSON.stringify(sourceFile.statements, null, '\t'));
}
printTypescript(`export class Icecream {flavor: string;}`)

I used this to figure out how to add an export statement to a class declaration. The code above produced the output below. The kind property will tell you exactly what token it is. All kind definitions can be found here: https://github.com/Microsoft/TypeScript/blob/8ddb2b61d2c996ab442b282ab9b36195ed697c13/lib/typescript.d.ts#L78

[[
{
"pos": 0,
"end": 50,
"flags": 0,
"kind": 240,
"modifiers": [
{
"pos": 0,
"end": 9,
"flags": 0,
"kind": 85
}
],
"name": {
"pos": 15,
"end": 24,
"flags": 0,
"escapedText": "Icecream"
},
"members": [
{
"pos": 26,
"end": 46,
"flags": 0,
"kind": 154,
"name": {
"pos": 26,
"end": 37,
"flags": 0,
"escapedText": "flavor"
},
"type": {
"pos": 38,
"end": 45,
"flags": 0,
"kind": 138
},
"modifierFlagsCache": 536870912
}
],
"modifierFlagsCache": 536870913
}
]

You can make it say export class foo {} by using the export key as a modifier.

Printing the finished (or unfinished result)

After you’re done assembling your nodes you can turn them into a string. You can print anything, a single lonely keyword, a half-finished function or an entire class.

function nodeText(n: ts.Node): string {
const resultFile = ts.createSourceFile(
'test.ts',
'',
ts.ScriptTarget.Latest,
false,
ts.ScriptKind.TS,
);
const printer = ts.createPrinter({
newLine: ts.NewLineKind.LineFeed,
});
const result = printer.printNode(
ts.EmitHint.Unspecified,
n,
resultFile,
);
return result;
}

Creating a Class

// output class foo {}const classNode = ts.createClassExpression(undefined, 'foo', undefined, undefined, undefined);

Creating a class which inherits another

// output class foo extends BaseClass {}const thingImExtending = ts.createIdentifier('BaseClass');const thingImExtendingAsAnExpression = ts.createExpressionWithTypeArguments(undefined, thingImExtending);const heritageClause = ts.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [thingImExtendingAsAnExpression]);const classDec = ts.createClassDeclaration(undefined, undefined, 'foo', undefined, [heritageClause], undefined);

Creating a constructor with a parameter, question mark, and a type argument.

/* output 
constructor(data?: Partial<foo>) {
super(data);
}
*/
const partialType = ts.createTypeReferenceNode(‘Partial’, [ts.createTypeReferenceNode('foo', undefined)]);const dataId = ts.createIdentifier(‘data’);const param = ts.createParameter(undefined, undefined, undefined, dataId, ts.createToken(ts.SyntaxKind.QuestionToken), partialType);const sup = ts.createSuper();const superCall = ts.createCall(sup, undefined, [dataId]);const statement = ts.createExpressionStatement(superCall);const block = ts.createBlock([statement], true);const cons = ts.createConstructor(undefined, undefined, [param], block);const classDec = ts.createClassDeclaration(undefined, undefined, 'foo', undefined, undefined, [cons]);

Properties

/* output
class foo {
propertyName: Number;
}
*/
const ref = ts.createTypeReferenceNode(‘Number’, []);const prop = ts.createProperty(undefined, undefined, ‘propertyName’, undefined, ref, undefined);const classDec = ts.createClassDeclaration(undefined, undefined, 'foo', undefined, undefined, [prop]);

Decorators

Decorators are particularly easy as they’re just function calls, this one has a parameter too;

/* output 
@niceDecorator
(“bar”)
class foo {
}
*/
const p = ts.createIdentifier(‘niceDecorator’);
const call = ts.createCall(p, undefined, [str]);
const dec = ts.createDecorator(call);
const classDec = ts.createClassDeclaration([dec], undefined, ‘foo’, undefined, undefined, undefined);

Object Literals

An object literal is created out of an array of PropertyAssignment

/* output
{"keyFoo": "foo", "keyBar": 1}
*/
const assignments: ts.PropertyAssignment[] = [];const key1 = "keyFoo";
const key2 = "keyBar";
const value1 = ts.createLiteral("foo");
const value2 = ts.createLiteral(1);

assignments.push(ts.createPropertyAssignment(key1, value1));
assignments.push(ts.createPropertyAssignment(key2, value2));
const obj = ts.createObjectLiteral(assignments);

--

--

Marvin Irwin
Marvin Irwin

Written by Marvin Irwin

React/Typescript/NodeJs/Blockchain Freelancer. 90CAD/hour. Happy to talk to you for for a few hours on some longshot proof of concept before staring work

Responses (3)