TypeScript's type is so powerful in compile time, but it is not available in runtime. Because it is stripped out in the transpiling process.
For example, we often validate input data, received from API or user input, in runtime. I prepared a simple validation function as the following.
validateUser.ts1type User = {2 id: number;3 name: string;4}56function validateUser(input: unknown): input is User {7 // TODO: ImplementME8 return true9}
Transpiling this code, I can get the following JavaScript code.
validateUser.js1"use strict";2function validateUser(input) {3 // TODO: ImplementME4 return true;5}
Type User is stripped. In build time, I could get the information of it. Something like, it has two properties. One is id. It has number type and the other is name, string type.
I need to implement this function carefully to run in runtime.
1function validateUser(input: unknown): input is User {2 return (3 typeof input === "object" &&4 input !== null &&5 "id" in input &&6 typeof input.id === "number" &&7 "name" in input &&8 typeof input.name === "string"9 );10}
This is a simple example, so there are other better ways. But, if I can use type information in runtime, it will be better.
TypeScript compiler API
Load source code
TypeScript compiler API is useful for manipulating TypeScript type.
To get type information from source code, we need to load the source code.
t.ts1import * as path from "node:path";2import * as ts from "typescript";34function t() {5 const file = path.resolve(__dirname, "t-sample.ts");6 const program = ts.createProgram([file], {7 declaration: true,8 emitDeclarationOnly: true,9 });1011 const source = program.getSourceFile(file);12 if (!source) {13 throw new Error(`No source file: ${file}`);14 }1516 console.log(source.getFullText());17}1819t()
t-sample.ts1type User = {2 name: string;3};
This code reads the source code, "t-sample.ts", in the same directory and prints the content.
1$ ts-node t.ts2type User = {3 name: string;4};56✨ Done in 1.27s.
Get type information
We get "source" object from "program". The type of it is ts.SourceFile. It is an interface extended from ts.Node. Source code is represented as a tree structure. ts.SourceFile is the root of the tree.
We can get type information traversing the tree.
1function showSyntaxTree(node: ts.Node, indent: string) {2 console.log(`${indent}${ts.SyntaxKind[node.kind]}`);3 ts.forEachChild(node, (child) => {4 showSyntaxTree(child, indent + " ");5 });6}
This function prints the nodes of tree. I added some comments. "Identifier" of "TypeAliasDeclaration" is "User", corresponding to type User. "Identifier" of "PropertySignature" is "name", corresponding to name: string.
1SourceFile2 TypeAliasDeclaration3 Identifier # User4 TypeLiteral5 PropertySignature6 Identifier # name7 StringKeyword8 EndOfFileToken