Intermediate Representation (IR)
The IR is the core data structure that bridges TypeScript and C#.
Purpose
The IR provides:
- Language-independent representation
- Semantic preservation
- Optimization opportunities
- Clean separation between parsing and emission
IrModule
Top-level structure representing a TypeScript file:
type IrModule = {
readonly filePath: string; // Relative path: "src/utils/math.ts"
readonly namespace: string; // C# namespace: "MyApp.utils"
readonly className: string; // C# class name: "math"
readonly imports: readonly IrImport[];
readonly exports: readonly IrExport[];
readonly body: readonly IrStatement[];
};
Imports
IrImport
type IrImport = {
readonly kind: "import";
readonly moduleSpecifier: string; // "./utils.js" or "@tsonic/dotnet/System.js"
readonly specifiers: readonly IrImportSpecifier[];
readonly isTypeOnly: boolean;
readonly resolved?: {
readonly isLocal: boolean;
readonly absolutePath?: string;
readonly clrNamespace?: string;
};
};
type IrImportSpecifier =
| { kind: "named"; name: string; alias?: string }
| { kind: "default"; alias: string }
| { kind: "namespace"; alias: string };
Exports
IrExport
type IrExport =
| { kind: "declaration"; declaration: IrStatement }
| { kind: "named"; name: string; alias?: string }
| { kind: "reexport"; moduleSpecifier: string; specifiers: ... };
Statements
Variable Declaration
type IrVariableDeclaration = {
readonly kind: "variableDeclaration";
readonly declarationKind: "const" | "let" | "var";
readonly declarations: readonly IrVariableDeclarator[];
};
type IrVariableDeclarator = {
readonly pattern: IrPattern;
readonly type?: IrType;
readonly init?: IrExpression;
};
Function Declaration
type IrFunctionDeclaration = {
readonly kind: "functionDeclaration";
readonly name: string;
readonly typeParameters?: readonly IrTypeParameter[];
readonly parameters: readonly IrParameter[];
readonly returnType?: IrType;
readonly body?: IrBlockStatement;
readonly isAsync: boolean;
readonly isGenerator: boolean;
readonly isExported: boolean;
};
Class Declaration
type IrClassDeclaration = {
readonly kind: "classDeclaration";
readonly name: string;
readonly typeParameters?: readonly IrTypeParameter[];
readonly extends?: IrReferenceType;
readonly implements?: readonly IrReferenceType[];
readonly members: readonly IrClassMember[];
readonly isExported: boolean;
readonly isAbstract: boolean;
};
type IrClassMember =
| IrPropertyDeclaration
| IrMethodDeclaration
| IrConstructorDeclaration;
Interface Declaration
type IrInterfaceDeclaration = {
readonly kind: "interfaceDeclaration";
readonly name: string;
readonly typeParameters?: readonly IrTypeParameter[];
readonly extends?: readonly IrReferenceType[];
readonly members: readonly IrInterfaceMember[];
readonly isExported: boolean;
};
Control Flow
type IrIfStatement = {
readonly kind: "ifStatement";
readonly test: IrExpression;
readonly consequent: IrStatement;
readonly alternate?: IrStatement;
};
type IrForStatement = {
readonly kind: "forStatement";
readonly init?: IrVariableDeclaration | IrExpression;
readonly test?: IrExpression;
readonly update?: IrExpression;
readonly body: IrStatement;
};
type IrForOfStatement = {
readonly kind: "forOfStatement";
readonly left: IrVariableDeclaration | IrPattern;
readonly right: IrExpression;
readonly body: IrStatement;
readonly isAwait: boolean;
};
Expressions
Literals
type IrLiteralExpression = {
readonly kind: "literal";
readonly value: string | number | boolean | null;
readonly raw: string;
};
Identifiers
type IrIdentifierExpression = {
readonly kind: "identifier";
readonly name: string;
readonly type?: IrType;
};
Binary Expressions
type IrBinaryExpression = {
readonly kind: "binary";
readonly operator: IrBinaryOperator;
readonly left: IrExpression;
readonly right: IrExpression;
};
type IrBinaryOperator =
| "+"
| "-"
| "*"
| "/"
| "%"
| "=="
| "!="
| "==="
| "!=="
| "<"
| ">"
| "<="
| ">="
| "&&"
| "||"
| "??"
| "&"
| "|"
| "^"
| "<<"
| ">>";
Call Expressions
type IrCallExpression = {
readonly kind: "call";
readonly callee: IrExpression;
readonly typeArguments?: readonly IrType[];
readonly arguments: readonly IrExpression[];
};
Member Access
type IrMemberExpression = {
readonly kind: "member";
readonly object: IrExpression;
readonly property: string | IrExpression;
readonly computed: boolean; // obj[prop] vs obj.prop
readonly optional: boolean; // obj?.prop
};
Object and Array Literals
type IrArrayExpression = {
readonly kind: "array";
readonly elements: readonly (IrExpression | null)[]; // null = hole
};
type IrObjectExpression = {
readonly kind: "object";
readonly properties: readonly IrObjectProperty[];
};
type IrObjectProperty = {
readonly key: string | IrExpression;
readonly value: IrExpression;
readonly computed: boolean;
readonly shorthand: boolean;
readonly method: boolean;
};
Types
Primitive Types
type IrPrimitiveType = {
readonly kind: "primitiveType";
readonly name: "number" | "string" | "boolean" | "null" | "undefined";
};
Reference Types
type IrReferenceType = {
readonly kind: "referenceType";
readonly name: string;
readonly typeArguments?: readonly IrType[];
readonly clrType?: string; // e.g., "System.Collections.Generic.List"
};
Array Types
type IrArrayType = {
readonly kind: "arrayType";
readonly elementType: IrType;
};
Function Types
type IrFunctionType = {
readonly kind: "functionType";
readonly parameters: readonly IrParameter[];
readonly returnType: IrType;
readonly typeParameters?: readonly IrTypeParameter[];
};
Tuple Types
type IrTupleType = {
readonly kind: "tupleType";
readonly elementTypes: readonly IrType[];
};
Generates ValueTuple<T1, T2, ...> in C#.
Union and Intersection
type IrUnionType = {
readonly kind: "unionType";
readonly types: readonly IrType[];
};
type IrIntersectionType = {
readonly kind: "intersectionType";
readonly types: readonly IrType[];
};
Patterns
Used in destructuring and parameters:
type IrPattern = IrIdentifierPattern | IrArrayPattern | IrObjectPattern;
type IrIdentifierPattern = {
readonly kind: "identifier";
readonly name: string;
readonly type?: IrType;
};
type IrArrayPattern = {
readonly kind: "array";
readonly elements: readonly (IrPattern | null)[];
readonly rest?: IrPattern;
};
type IrObjectPattern = {
readonly kind: "object";
readonly properties: readonly IrObjectPatternProperty[];
readonly rest?: IrPattern;
};
Building IR
The IR is built by traversing the TypeScript AST:
// Simplified flow
const buildIrModule = (
sourceFile: ts.SourceFile,
checker: ts.TypeChecker
): IrModule => {
const body = sourceFile.statements.map((stmt) =>
convertStatement(stmt, checker)
);
const imports = extractImports(sourceFile);
const exports = extractExports(sourceFile, body);
return {
filePath: getRelativePath(sourceFile.fileName),
namespace: computeNamespace(sourceFile.fileName),
className: computeClassName(sourceFile.fileName),
imports,
exports,
body,
};
};