VINCENT OGLOBLINSKY
@vogloblinsky
Vincent Ogloblinsky
Frontend software architect
SII Ouest - France
@vogloblinsky
ES5
ES6
ES7, ESNext
TypeScript
A compiler is a computer program that transforms source code written in a programming language into another computer language [...] The most common reason for converting source code is to create an executable program.
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
let greeter = new Greeter("world");
let button = document.createElement('button');
button.textContent = "Say Hello";
button.onclick = function() {
alert(greeter.greet());
}
document.body.appendChild(button);
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
let greeter = new Greeter("world");
let button = document.createElement('button');
button.textContent = "Say Hello";
button.onclick = function() {
alert(greeter.greet());
}
document.body.appendChild(button);
var Greeter = /** @class */ (function () {
function Greeter(message) {
this.greeting = message;
}
Greeter.prototype.greet = function () {
return "Hello, " + this.greeting;
};
return Greeter;
}());
var greeter = new Greeter("world");
var button = document.createElement('button');
button.textContent = "Say Hello";
button.onclick = function () {
alert(greeter.greet());
};
document.body.appendChild(button);
Parsing
Transforming
Generating
take raw code
and turns it into
a more abstract representation
2 steps:
lexical analysis
syntax analysis
Parsing
Transforming
Generating
Lexical analysis
let message = 'hello'
split code into tokens
Parsing
Transforming
Generating
Syntax analysis
reformat tokens into a representation describing each part of the syntax and their relations
Parsing
Transforming
Generating
Syntax analysis
"tokens": [
{
"type": "Keyword",
"value": "let"
},
{
"type": "Identifier",
"value": "message"
},
{
"type": "Punctuator",
"value": "="
},
{
"type": "String",
"value": "\"hello DEVOXX\""
}
]
{
"type": "Program",
"body": [
{
"type": "VariableDeclaration",
"declarations": [
{
"type": "VariableDeclarator",
"id": {
"type": "Identifier",
"name": "message"
},
"init": {
"type": "Literal",
"value": "hello DEVOXX",
}
}
],
"kind": "let"
}
]
}
AST
Abstract Syntax Tree
Parsing
Transforming
Generating
take the AST
and make transformations for each nodes into final language context
Parsing
Transforming
Generating
Generation of code in the desired output
Stringify each nodes
Knows how to print them
Parsing
Transforming
Generating
TypeScript
compiler
Scanner
Parser
Checker
The scanner is driven by the parser
First internal part of "parsing"
Creates a tokens stream
Binder
Emitter
Parser
Checker
Binder
Emitter
const ts = require('typescript')
const scanner = ts.createScanner(ts.ScriptTarget.Latest, true);
let sourceCode = `var foo:number = "5";`
function initializeState(text) {
scanner.setText(text);
scanner.setOnError((message) => {console.error(message);});
scanner.setScriptTarget(ts.ScriptTarget.ES5);
scanner.setLanguageVariant(ts.LanguageVariant.Standard);
}
function syntaxKindToName(kind) {
return ts.SyntaxKind[kind];
}
initializeState(sourceCode);
let token = scanner.scan();
while (token != ts.SyntaxKind.EndOfFileToken) {
console.log(token, syntaxKindToName(token));
token = scanner.scan();
}
104 'VarKeyword'
71 'Identifier'
56 'ColonToken'
133 'NumberKeyword'
58 'FirstAssignment'
9 'StringLiteral'
25 'SemicolonToken'
Scanner
Parser
Checker
The parser is driven by a program
AST is generated here
Binder
Emitter
Scanner
Parser
Checker
Binder
Emitter
Scanner
let parsedSourceFile =
ts.createSourceFile(
'file.ts',
sourceCode,
ts.ScriptTarget.ES5,
true
);
SourceFileObject {
pos: 0,
end: 21,
flags: 0,
transformFlags: undefined,
parent: undefined,
kind: 265,
text: 'var foo:number = "5";',
bindDiagnostics: [],
languageVersion: 1,
fileName: 'foo.ts',
languageVariant: 0,
isDeclarationFile: false,
scriptKind: 3,
referencedFiles: [],
typeReferenceDirectives: [],
amdDependencies: [],
moduleName: undefined,
checkJsDirective: undefined,
statements:
[ NodeObject {
pos: 0,
end: 21,
flags: 0,
transformFlags: undefined,
parent: [Circular],
kind: 208,
decorators: undefined,
modifiers: undefined,
declarationList: [Object],
modifierFlagsCache: 536870912 },
pos: 0,
end: 21 ],
endOfFileToken: TokenObject { pos: 21, end: 21, flags: 0, parent: [Circular], kind: 1 },
externalModuleIndicator: undefined,
nodeCount: 8,
identifierCount: 1,
identifiers: Map { 'foo' => 'foo' },
parseDiagnostics: [] }
Parser
Checker
Binder
Emitter
Scanner
Parser
Checker
Binder
Emitter
Scanner
Parser
Checker
The binder connects parts into coherent type system
Creates symbols
1st semantic pass
Binder
Emitter
Scanner
Parser
Checker
Symbols
connect declaration nodes in the AST to other declarations contributing to the same entity
Binder
Emitter
Scanner
Checker
Emitter
Scanner
ts.bindSourceFile(parsedSourceFile, {
target: ts.ScriptTarget.ES5,
module: ts.ModuleKind.CommonJS
});
...
initializer:
TokenObject {
pos: 16,
end: 20,
flags: 0,
parent: [Circular],
kind: 9,
text: '5',
transformFlags: 536870912 },
symbol:
SymbolObject {
flags: 1,
escapedName: 'foo',
declarations: [ [Circular] ],
valueDeclaration: [Circular],
parent: undefined }
Parser
Binder
Parser
Checker
Binder
Emitter
Scanner
Parser
Checker
The checker driven by a program
2nd semantic pass
- figure out relationships between symbols
- assign types to symbols
- generate semantic diagnostics (errors)
Binder
Emitter
Scanner
Emitter
Scanner
const fileName = './src/code.ts';
const program = ts.createProgram([fileName], {
noEmitOnError: true,
noImplicitAny: true,
target: ts.ScriptTarget.ES5,
module: ts.ModuleKind.CommonJS,
outDir: 'dist'
});
const diagnostics = ts.getPreEmitDiagnostics(program);
console.log(diagnostics);
[ { file:
SourceFileObject {...},
start: 146,
length: 14,
code: 2322,
category: 1,
messageText: 'Type \'number\' is not assignable to type \'string\'.' } ]
Parser
Checker
Binder
Parser
Checker
The emitter generate the desired output :
.js, .d.ts, or .js.map
use .emit of a program
internally use a transformer
print the final code
Binder
Emitter
Scanner
Scanner
const fileName = './src/code.ts'; // var foo:number = '5';
const program = ts.createProgram([fileName],
{
noEmitOnError: true,
noImplicitAny: true,
target: ts.ScriptTarget.ES5,
module: ts.ModuleKind.CommonJS,
outDir: 'dist'
});
let emitResult = program.emit();
console.log(emitResult);
{ diagnostics:
[ { file: [Object],
messageText: 'Type \'"5"\' is not assignable to type \'number\'.' } ],
sourceMaps: undefined,
emittedFiles: undefined,
emitSkipped: true }
Parser
Binder
Checker
Emitter
Scanner
const fileName = './src/code.ts'; // var foo:number = 5;
const program = ts.createProgram([fileName],
{
noEmitOnError: true,
noImplicitAny: true,
target: ts.ScriptTarget.ES5,
module: ts.ModuleKind.CommonJS,
outDir: 'dist'
});
let emitResult = program.emit();
console.log(emitResult);
{ emitSkipped: false,
diagnostics: [],
emittedFiles: undefined,
sourceMaps: undefined }
Parser
Binder
Checker
Emitter
linting
analysing complexity
documentation
API conformance
statistics
lint & do semantic ruling
lint with rules using internal walker
apply patch using normal string APIs
// home-paths.ts
export const PATHS = {
home: 'homeimported'
};
// home-routing.module.ts
import { PATHS } from './home-paths';
const HOME_ROUTES: Routes = [
{
path: PATHS.home,
component: HomeComponent
}
];
PropertyAccessExpression
StringLiteral
@schematics
exemple: adding declaration in a module
function add(a, b) {
return a + b;
}
add(5, 6);
function add(a: number, b: number) {
return a + b;
}
add(5, 6);
Generate a visual graph of your JavaScript module dependencies
Works with TypeScript files too
Generate sound with
Angular/TypeScript AST
How to be* a compiler — make a compiler with JavaScript
https://medium.com/@kosamari/how-to-be-a-compiler-make-a-compiler-with-javascript-4a8a13d473b4
TypeScript Deep Dive
https://basarat.gitbooks.io/typescript/docs/compiler/overview.html
TypeScript - Architectural Overview
https://github.com/Microsoft/TypeScript/wiki/Architectural-Overview
TypeScript - Compiler Internals
https://github.com/Microsoft/TypeScript/wiki/Compiler-Internals
The Rise of TypeScript?
https://developer.telerik.com/featured/the-rise-of-typescript/
Moving from JavaScript to TypeScript at Slack
https://www.infoq.com/news/2017/04/going-typescript-slack
Compilers are the New Frameworks
https://tomdale.net/2017/09/compilers-are-the-new-frameworks/
The Future of JavaScript Will Be Less JavaScript
https://medium.com/@mrdaniel/the-future-of-javascript-will-be-less-javascript-cea373eb57fd
Ask me anything during the conference
Sketch-notes : bit.ly/2AYVcp7