JavaScript ES6
& Typescript
We expect cooperation from all participants to help ensure a safe environment for everybody.
We treat everyone with respect, we refrain from using offensive language and imagery, and we encourage to report any derogatory or offensive behavior to a member of the JSLeague community.
We provide a fantastic environment for everyone to learn and share skills regardless of gender, gender identity and expression, age, sexual orientation, disability, physical appearance, body size, race, ethnicity, religion (or lack thereof), or technology choices.
We value your attendance and your participation in the JSLeague community and expect everyone to accord to the community Code of Conduct at all JSLeague workshops and other events.
Code of conduct
Whoami
Alexandru Albu
Trainer @JSLeague
frontend engineer @10yo
design: photoshop, illustrator
development: javascript. python, sql, mongo
devops: docker
and gaming and basketball
Overview
JavaScript ES6 & Typescript
JavaScript ES6 & Typescript
Agenda
// ES6
Block scope variables
Template strings
Enhanced Objects
Arrow functions
Classes
Destructuring
Spread and rest
Modules
Iterators
Async / Await
// Typescript
Overview
Type System
Classes
Interfaces
Union / Intersection types
Enums
Generics
Decorators
Block scope variables
JavaScript ES6 & Typescript
JavaScript ES6 & Typescript
function getColor(condition) {
if (condition) {
var value = "blue";
// other code
return value;
} else {
return null;
}
}
ES5 Variable Hoisting
JavaScript ES6 & Typescript
function getColor(condition) {
var value; // undefined
if (condition) {
var value = "blue";
// other code
return value;
} else {
// value = undefined
return null;
}
// value = undefined
}
ES5 Variable Hoisting
variables are hoisted to the top of the enclosing function
JavaScript ES6 & Typescript
for (var i = 0; i < 10; i++) {
process(items[i]);
}
console.log(i); // 10
ES5 Variables in Loops
JavaScript ES6 & Typescript
var funcs = [];
for (var i = 0; i < 10; i++) {
funcs.push(function() { console.log(i); });
}
funcs.forEach(function(func) {
func(); // 10, 10, 10....
});
ES5 Functions in Loops
JavaScript ES6 & Typescript
- Block scope declarations - variables that are inaccessible outside of a given block scope
-
Block scopes (lexical scopes)
- Inside of a function
- Inside of a block ( between { and } )
-
ES6 introduces 2 new type of variable declarations:
- let
- const
JavaScript ES6 & Typescript
function getColor(condition) {
if (condition) {
let value = "blue";
// other code
return value;
} else {
// value doesn't exist here - ReferenceError
return null;
}
// value doesn't exist here - ReferenceError
}
LET
ReferenceError is thrown outside of scope
JavaScript ES6 & Typescript
var count = 30;
// Syntax error
let count = 40;
Redeclarating LET
LET cannot be redeclarated in the same scope
JavaScript ES6 & Typescript
var count = 30;
// Does not throw an error
if (condition) {
let count = 40; // shadows the outer variable inside this scope
// more code
}
Redeclarating LET
LET can be redeclarated in another scope
JavaScript ES6 & Typescript
// Valid constant
const maxItems = 30;
// Syntax error: missing initialization
const name;
maxItems = 6; // throws error
var message = "Hello!";
let age = 25;
// Each of these would throw an error.
const message = "Goodbye!";
const age = 30;
CONST
CONST content / reference does not change
JavaScript ES6 & Typescript
const person = {
name: "Andrei"
};
// works
person.name = "George";
// throws an error - reinitialization
person = {
name: "George"
};
CONST
CONST prevents modification of binding, not the value
JavaScript ES6 & Typescript
if (condition) {
console.log(typeof value); // ReferenceError!
let value = "blue";
}
console.log(typeof value); // "undefined"
if (condition) {
let value = "blue";
}
TDZ (Temporal Dead Zone)
LET and CONST cannot be accessed before declaration
JavaScript ES6 & Typescript
for (let i = 0; i < 10; i++) {
process(items[i]);
}
// i is not accessible here - throws an error
console.log(i);
var funcs = [];
for (let i = 0; i < 10; i++) {
funcs.push(function() {
console.log(i);
});
}
funcs.forEach(function(func) {
func(); // 0, 1, 2, 3,...
})
Loops - LET
LET creates a new i each time
JavaScript ES6 & Typescript
var funcs = [];
// throws an error after one iteration
for (const i = 0; i < 10; i++) {
funcs.push(function() {
console.log(i);
});
}
var funcs = [],
object = {
a: true,
b: true,
c: true
};
// doesn't cause an error
for (const key in object) {
funcs.push(function() {
console.log(key);
});
}
Loops - CONST
Template strings
JavaScript ES6 & Typescript
JavaScript ES6 & Typescript
New string methods:
- includes() - check if the given text is found anywhere within the string.
- startsWith() - check if the given text is found at the beginning of the string
- endsWith() - check if the given text is found at the end of the string
- repeat() - returns a new string containing the original string repeated the specified number of times.
JavaScript ES6 & Typescript
var msg = "Hello world!";
console.log(msg.startsWith("Hello")); // true
console.log(msg.endsWith("!")); // true
console.log(msg.includes("o")); // true
console.log(msg.startsWith("o")); // false
console.log(msg.endsWith("world!")); // true
console.log(msg.includes("x")); // false
console.log(msg.startsWith("o", 4)); // true
console.log(msg.endsWith("o", 8)); // true
console.log(msg.includes("o", 8)); // false
console.log("x".repeat(3)); // "xxx"
console.log("hello".repeat(2)); // "hellohello"
console.log("abc".repeat(4)); // "abcabcabcabc"
JavaScript ES6 & Typescript
Template strings
- Multiline strings A formal concept of multiline strings.
- Basic string formatting The ability to substitute parts of the string for values contained in variables.
- HTML escaping The ability to transform a string such that it is safe to insert into HTML.
JavaScript ES6 & Typescript
let message = `Hello world!`;
console.log(message); // "Hello world!"
console.log(typeof message); // "string"
console.log(message.length); // 12
strings delimited by backquotes (`) instead of quotes
JavaScript ES6 & Typescript
// old syntax bug
var message = "Multiline \
string";
console.log(message); // "Multiline string"
var message = "Multiline \n\
string";
console.log(message); // "Multiline
// string"
var message = [
"Multiline ",
"string"
].join("\n");
let message = "Multiline \n" +
"string";
ES5 Multiline strings
JavaScript ES6 & Typescript
let message = `Multiline
string`;
console.log(message); // "Multiline
// string"
console.log(message.length); // 16
Preserve newlines
JavaScript ES6 & Typescript
let message = `Multiline
string`;
console.log(message); // "Multiline
// string"
console.log(message.length); // 31
Preserve tabs
JavaScript ES6 & Typescript
// ES5
var message = "<table>" +
"<tr>Jane</tr>" +
"<tr>Bond&</tr>" +
"<tr>Lars</tr>" +
"<tr>Croft</tr>" +
"</table>";
// ES6
let message = `
<table>
<tr>Jane</tr>
<tr>Bond&</tr>
<tr>Lars</tr>
<tr>Croft</tr>
</table>`;
Better HTML strings
JavaScript ES6 & Typescript
let name = "JSLeague",
message = `Hello, ${name}.`;
console.log(message); // "Hello, JSLeague."
let count = 10,
price = 0.25,
message = `${count} items cost $${(count * price).toFixed(2)}.`;
console.log(message); // "10 items cost $2.50."
Easier substitutions
JavaScript ES6 & Typescript
let count = 10,
price = 0.25,
message = passthru`${count} items cost $${(count * price).toFixed(2)}.`;
function passthru(literals, ...substitutions) {
// literals: [ "", " items cost $", "." ]
// substitutions [ 10, "2.50" ]
// return a string
}
Tagged templates
- literals - an array containing the literal strings as interpreted by JavaScript
- substitutions - the interpreted value of each substitution
Enhanced Objects
JavaScript ES6 & Typescript
JavaScript ES6 & Typescript
// ES5
function createPerson(name, age) {
return {
name: name,
age: age
};
}
// ES6
function createPerson(name, age) {
return {
name,
age
};
}
Property initializer shorthand
JavaScript ES6 & Typescript
// ES5
var person = {
name: "Nicholas",
sayName: function() {
console.log(this.name);
}
};
// ES6
var person = {
name: "Nicholas",
sayName() {
console.log(this.name);
}
};
Concise Methods
JavaScript ES6 & Typescript
let person = {
// method
getGreeting() {
return "Hello";
}
};
// not a method
function shareGreeting() {
return "Hi!";
}
Formal Method Definition
A method is a function that has an internal [[HomeObject]] property containing the object to which the method belongs
JavaScript ES6 & Typescript
let person = {
getGreeting() {
return "Hello";
}
};
// prototype is person
let friend = {
getGreeting() {
return super.getGreeting() + ", hi!";
}
};
Object.setPrototypeOf(friend, person);
console.log(friend.getGreeting()); // "Hello, hi!"
Using super() for prototype calls
JavaScript ES6 & Typescript
// ES5
var person = {},
lastName = "last name";
person["first name"] = "John";
person[lastName] = "Doe";
console.log(person["first name"]); // "John"
console.log(person[lastName]); // "Doe"
// ES6
var lastName = "last name";
var person = {
"first name": "John",
[lastName]: "Doe"
};
console.log(person["first name"]); // "John"
console.log(person["last name"]); // "Doe"
Computed property names
JavaScript ES6 & Typescript
// ES5
var suffix = " name";
var person = {};
person["first" + suffix] = "John";
console.log(person["first name"]); // "John"
// ES6
var suffix = " name";
var person = {
["first" + suffix]: "John",
["last" + suffix]: "Doe"
};
console.log(person["first name"]); // "John"
console.log(person["last name"]); // "Doe"
Computed property names
JavaScript ES6 & Typescript
console.log(+0 == -0); // true
console.log(+0 === -0); // true
console.log(Object.is(+0, -0)); // false
console.log(NaN == NaN); // false
console.log(NaN === NaN); // false
console.log(Object.is(NaN, NaN)); // true
console.log(5 == 5); // true
console.log(5 == "5"); // true
console.log(5 === 5); // true
console.log(5 === "5"); // false
console.log(Object.is(5, 5)); // true
console.log(Object.is(5, "5")); // false
New methods - Object.is()
fix the remaining quirks of the identically equals operator
JavaScript ES6 & Typescript
var o1 = { a: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };
var obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1); // { a: 1, b: 2, c: 3 }, target object itself is changed.
var safeObj = Object.assign({}, o1, o2, o3);
console.log(safeObj); // { a: 1, b: 2, c: 3 }
console.log(o1); // { a: 1 }, o1 is the same.
var cloneObj = Object.assign({}, o1);
console.log(cloneObj); // { a: 1 }
New methods - Object.assign()
copy the values of all enumerable own properties from one or more source objects to a target object
Arrow Functions
JavaScript ES6 & Typescript
JavaScript ES6 & Typescript
- The value of this, super, arguments, and new.target inside of the function is by the closest containing non-arrow function.
- Functions defined with a new syntax that uses an “arrow” (=>)
- Difference from "classic" functions
- Cannot be called with new - no new.target binding
- No prototype - no super binding
- Can’t change this
- No arguments object
- No duplicate named parameters
JavaScript ES6 & Typescript
// ES5 function
var reflect = function(value) {
return value;
};
// ES6 expanded
const reflect = (value) => { return value };
// ES6 short
const reflect = value => value;
- no parenthesis if only one argument
- no block (brackets) needed if only return statement
JavaScript ES6 & Typescript
// ES5 equivalent function
var sum = function(num1, num2) {
return num1 + num2;
};
// ES6
const sum = (num1, num2) => num1 + num2;
Parenthesis needed for 2 or more arguments
JavaScript ES6 & Typescript
// ES5 equivalent function
var getName = function() {
return "John";
};
// ES6
const getName = () => "John";
Empty parenthesis needed if no arguments
JavaScript ES6 & Typescript
// ES5 equivalent function
var getTempItem = function(id) {
return {
id: id,
name: "Temp"
};
};
// ES6
const getTempItem = id => ({ id: id, name: "Temp" });
When returning an object, it's necessary to wrap it in ()
JavaScript ES6 & Typescript
var PageHandler = {
id: "123456",
init: function() {
document.addEventListener("click", function(event) {
this.doSomething(event.type);
}, false);
},
doSomething: function(type) {
console.log("Handling " + type + " for " + this.id);
}
};
PageHandler.init();
event listeners usually bind this to the target of the event
JavaScript ES6 & Typescript
var PageHandler = {
id: "123456",
init: function() {
document.addEventListener("click", (function(event) {
this.doSomething(event.type); // no error
}).bind(this), false);
},
doSomething: function(type) {
console.log("Handling " + type + " for " + this.id);
}
};
PageHandler.init();
we can change the this binding (among other ways) by using the .bind() method
JavaScript ES6 & Typescript
function UiComponent {
var that = this;
var button = document.getElementById(#myButton);
button.addEventListener(click,
function () {
console.log(CLICK);
that.handleClick();
});
}
UiComponent.prototype.handleClick = function () { ... };
we can also keep a reference to this
JavaScript ES6 & Typescript
var PageHandler = {
id: "123456",
init: function() {
document.addEventListener("click",
event => this.doSomething(event.type), false);
},
doSomething: function(type) {
console.log("Handling " + type + " for " + this.id);
}
};
arrow functions don't bind to this - the value of this inside an arrow function can only be determined by looking up the scope chain
JavaScript ES6 & Typescript
var arr = [5, 6, 13, 0, 1, 18, 23];
// ES5
var sum = arr.reduce(function (a, b) {
return a + b;
}); // 66
var even = arr.filter(function (v) {
return v % 2 == 0;
} // [6, 0, 18]
var double = arr.map(function (v){
return v * 2;
)} // [10, 12, 26, 0, 2, 36, 46]
// ES6
var sum = arr.reduce((a, b) => a + b); // 66
var even = arr.filter(v => v % 2 == 0); // [6, 0, 18]
var double = arr.map(v => v * 2); // [10, 12, 26, 0, 2, 36, 46]
arrow functions simplify array methods
Classes
JavaScript ES6 & Typescript
JavaScript ES6 & Typescript
function Person(name) {
this.name = name;
}
PersonType.prototype.sayName = function() {
console.log(this.name);
};
let person = new Person("Andrei");
person.sayName(); // outputs "Andrei"
console.log(person instanceof Person); // true
console.log(person instanceof Object); // true
console.log(typeof Person); // "function"
ES5 "Class"
JavaScript ES6 & Typescript
JavaScript ES6 & Typescript
class PersonClass {
constructor(name) { // same as Person constructor function
this.name = name;
}
sayName() { // same as Person.prototype.sayName
console.log(this.name);
}
}
let person = new PersonClass("Andrei");
person.sayName(); // outputs "Andrei"
console.log(person instanceof PersonClass); // true
console.log(person instanceof Object); // true
console.log(typeof PersonClass); // "function"
console.log(typeof PersonClass.prototype.sayName); // "function"
ES6 Class
JavaScript ES6 & Typescript
Differences between classes and functions
- Class declarations, unlike function declarations, are not hoisted
- All code inside of class declarations runs in strict mode automatically
- All methods are non-enumerable
- All methods will throw an error if you try to call them with new
- Calling the class constructor without new throws an error
- Attempting to overwrite the class name within a class method throws an error
JavaScript ES6 & Typescript
let PersonClass = class {
// equivalent of the PersonType constructor
constructor(name) {
this.name = name;
}
// equivalent of PersonType.prototype.sayName
sayName() {
console.log(this.name);
}
};
let person = new PersonClass("Andrei");
person.sayName(); // "Andrei"
console.log(person instanceof PersonClass); // true
console.log(person instanceof Object); // true
console.log(typeof PersonClass); // "function"
console.log(typeof PersonClass.prototype.sayName); // "function"
Anonymous classes
JavaScript ES6 & Typescript
let PersonClass = class PersonClass2 {
// equivalent of the PersonType constructor
constructor(name) {
this.name = name;
}
// equivalent of PersonType.prototype.sayName
sayName() {
console.log(this.name);
}
};
console.log(typeof PersonClass); // "function"
console.log(typeof PersonClass2); // "undefined"
Named class expressions
JavaScript ES6 & Typescript
// ES5
let Person = (function() {
"use strict";
const Person = function(name) {
if (typeof new.target === "undefined") {
throw new Error("Constructor must be called with new.");
}
this.name = name;
}
Object.defineProperty(CustomHTMLElement.prototype, "name", {
enumerable: false,
configurable: true,
get: function() {
return this.name;
},
set: function(value) {
this.name= value;
}
});
return Person;
}());
Accessor properties
JavaScript ES6 & Typescript
// ES6
class Person {
constructor(name) {
this.name = name;
}
get name() {
return this.name;
}
set name(value) {
this.name = value;
}
}
var descriptor = Object.getOwnPropertyDescriptor(Person.prototype, "name");
console.log("get" in descriptor); // true
console.log("set" in descriptor); // true
console.log(descriptor.enumerable); // false
Accessor properties
JavaScript ES6 & Typescript
// ES5
function PersonType(name) {
this.name = name;
}
// static method
PersonType.create = function(name) {
return new PersonType(name);
};
// instance method
PersonType.prototype.sayName = function() {
console.log(this.name);
};
var person = PersonType.create("Andrei");
Static methods
JavaScript ES6 & Typescript
// ES6
class PersonClass {
constructor(name) { // same as PersonType constructor
this.name = name;
}
sayName() { // same as PersonType.prototype.sayName
console.log(this.name);
}
// equivalent of PersonType.create
static create(name) {
return new PersonClass(name);
}
}
let person = PersonClass.create("Andrei");
Static methods
JavaScript ES6 & Typescript
// ES5
function Rectangle(length, width) {
this.length = length;
this.width = width;
}
Rectangle.prototype.getArea = function() {
return this.length * this.width;
};
function Square(length) {
Rectangle.call(this, length, length);
}
Square.prototype = Object.create(Rectangle.prototype, {
constructor: {
value:Square,
enumerable: true,
writable: true,
configurable: true
}
});
var square = new Square(3);
console.log(square.getArea()); // 9
console.log(square instanceof Square); // true
console.log(square instanceof Rectangle); // true
Inheritance
JavaScript ES6 & Typescript
// ES6
class Rectangle {
constructor(length, width) {
this.length = length;
this.width = width;
}
getArea() {
return this.length * this.width;
}
}
class Square extends Rectangle {
constructor(length) {
super(length, length); // same as Rectangle.call(this, length, length)
}
}
var square = new Square(3);
console.log(square.getArea()); // 9
console.log(square instanceof Square); // true
console.log(square instanceof Rectangle); // true
Inheritance
Derived classes require you to use super() if you specify a constructor
JavaScript ES6 & Typescript
// ES6
class Square extends Rectangle {
constructor(length) {
super(length, length);
}
// override and shadow Rectangle.prototype.getArea()
getArea() {
return this.length * this.length;
}
}
class Square extends Rectangle {
constructor(length) {
super(length, length);
}
// override, shadow, and call Rectangle.prototype.getArea()
getArea() {
return super.getArea();
}
}
Shadowing methods
You can call the base class version of the method by using the super
JavaScript ES6 & Typescript
// abstract base class
class Shape {
constructor() {
if (new.target === Shape) {
throw new Error("This class cannot be instantiated directly.")
}
}
}
class Rectangle extends Shape {
constructor(length, width) {
super();
this.length = length;
this.width = width;
}
}
var x = new Shape(); // throws error
var y = new Rectangle(3, 4); // no error
console.log(y instanceof Shape); // true
Abstract classes
Destructuring
JavaScript ES6 & Typescript
JavaScript ES6 & Typescript
the process of breaking a data structure down into smaller parts
JavaScript ES6 & Typescript
let toDoItem = {
name: "Walk dog",
isDone: false
};
// ES5
// extract data from the object
let name = toDoItem.name;
let isDone = toDoItem.isDone;
// ES6
let { name, isDone } = toDoItem;
console.log(name); // "Walk dog"
console.log(isDone); // false
JavaScript ES6 & Typescript
// safe init
let toDoItem = {
name: "Walk dog",
isDone: false
};
let { name, isDone, tag } = toDoItem;
console.log(name); // "Walk dog"
console.log(isDone); // false
console.log(tag); // undefined
// default values
let toDoItem = {
name: "Walk dog",
isDone: false
};
let { name, isDone, tag = "Home" } = toDoItem;
console.log(name); // "Walk dog"
console.log(isDone); // false
console.log(tag); // "Home"
Default values
JavaScript ES6 & Typescript
// renaming
let toDoItem = {
name: "Walk dog",
isDone: false
};
let { name: toDoName, isDone: doneState } = toDoItem;
console.log(toDoName); // "Walk dog"
console.log(doneState); // false
// with default values
let toDoItem = {
name: "Walk dog"
};
let { name: toDoName, isDone: doneState = false } = toDoItem;
console.log(toDoName); // "Walk dog"
console.log(doneState); // false
Renaming variables
JavaScript ES6 & Typescript
let toDoItem = {
details: {
name: "Walk dog",
dueDate: "11.03.2017"
},
isDone: false
};
// extract toDoItem.details.name
let { details: { name: toDoName } } = toDoItem;
console.log(toDoName) // "Walk dog"
Multilevel
JavaScript ES6 & Typescript
// Array
let colors = [ "red", "green", "blue" ];
let [ firstColor, secondColor ] = colors;
console.log(firstColor); // "red"
console.log(secondColor); // "green"
// Nested
let colors = [ "red", [ "green", "lightgreen" ], "blue" ];
let [ firstColor, [ secondColor ] ] = colors;
console.log(firstColor); // "red"
console.log(secondColor); // "green"
// Skip values
let colors = [ "red", "green", "blue" ];
let [ , , thirdColor ] = colors;
console.log(thirdColor); // "blue"
// Swapping
let a = 1,
b = 2;
[ a, b ] = [ b, a ];
console.log(a); // 2
console.log(b); // 1
Array destructuring
JavaScript ES6 & Typescript
let mixed = {
one: 1,
two: 2,
values: [3, 4, 5]
};
let { one: a, two: b, values: [c, , e] } = mixed;
console.log(a); // 1
console.log(b); // 2
console.log(c); // 3
console.log(e); // 5
Mixed destructuring
JavaScript ES6 & Typescript
// Wihout destructuring
const animal = {
name: 'Dog',
sound: 'wof'
};
function makeSound(options) {
options.name = options.name || 'animal';
console.log(`The ${options.animal} goes ${options.sound}`)
}
makeSound(animal);
// With destructuring
const animal = {
name: 'Dog',
sound: 'wof'
};
function makeSound({name = 'animal', sound}) {
console.log(`The ${name} goes ${sound}`)
}
makeSound(animal);
Destructured function parameters
JavaScript ES6 & Typescript
function setCookie(name, value,
{
secure = false,
path = "/",
domain = "example.com",
expires = new Date(Date.now() + 360000000)
} = {}
) {
// ...
}
Spread and Rest
JavaScript ES6 & Typescript
JavaScript ES6 & Typescript
function logNumbers(a, b, c) {
console.log(a)
console.log(b)
console.log(c)
}
const array = [1,2,3];
logNumbers(...array); // 1 2 3
Spread operator
the spread operator allows you to specify an array that should be split and have its items passed in as separate arguments to a function
JavaScript ES6 & Typescript
// Array
const array = [1,2,3];
console.log([...array, 4, 5]); // [1, 2, 3, 4, 5]
// Set
let set = new Set([1, 2, 3, 3, 3, 4, 5]),
array = [...set];
console.log(array); // [1,2,3,4,5]
// Object
var obj = {'key1': 'value1'};
var array = [...obj]; // TypeError: obj is not iterable
Structures
JavaScript ES6 & Typescript
// Concatenation
const arr1 = [1,2,3];
const arr2 = [2,3,4];
const arr3 = [...arr1, 8, ...arr2];
console.log(arr3); // [1, 2, 3, 8, 2, 3, 4]
// Copy
const arr1 = [1,2,3];
const arr2 = [...arr1]
console.log(arr1); // [1, 2, 3]
console.log(arr2); // [1, 2, 3]
console.log(arr1 === arr2); // false
Array
JavaScript ES6 & Typescript
// Concatenation
const obj1 = {a: 'a', b: 'b'};
const obj2 = {c: 'c', ...obj1};
console.log(obj2); // {a: 'a', b: 'b', c: 'c'}
// Overwrite
const obj1 = {a: 'a', b: 'b', c: 'c'};
const obj2 = {c: 'd', ...obj1};
console.log(obj2); // {a: 'a', b: 'b', c: 'd'}
Object
JavaScript ES6 & Typescript
function pick(object) {
let result = Object.create(null);
// start at the second parameter
for (let i = 1, len = arguments.length; i < len; i++) {
result[arguments[i]] = object[arguments[i]];
}
return result;
}
let book = {
title: "Understanding ECMAScript 6",
author: "Nicholas C. Zakas",
year: 2015
};
let bookData = pick(book, "author", "year");
console.log(bookData.author); // "Nicholas C. Zakas"
console.log(bookData.year); // 2015
Unnamed parameters in ES5
JavaScript ES6 & Typescript
function pick(object, ...keys) {
let result = Object.create(null);
for (let i = 0, len = keys.length; i < len; i++) {
result[keys[i]] = object[keys[i]];
}
return result;
}
Rest parameters in ES6
The rest parameter becomes an Array containing the rest of the parameters passed to the function
JavaScript ES6 & Typescript
function pick(object, ...keys, last) {
let result = Object.create(null);
for (let i = 0, len = keys.length; i < len; i++) {
result[keys[i]] = object[keys[i]];
}
return result;
}
Restrictions
Can't have a named parameter after rest parameters
JavaScript ES6 & Typescript
let object = {
set name(...value) {
// do something
}
};
Restrictions
Can't use rest parameter in setter
JavaScript ES6 & Typescript
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
console.log(x); // 1
console.log(y); // 2
console.log(z); // { a: 3, b: 4 }
Objects
Rest properties collect the remaining own enumerable property keys that are not already picked off by the destructuring pattern
Modules
JavaScript ES6 & Typescript
JavaScript ES6 & Typescript
Modules
- ES6 way to solve the "everything is in one scope" problem
- Module code automatically runs in strict mode
- Variables created in the top level of a module aren’t automatically added to the shared global scope.
- The value of this in the top level of a module is undefined.
- Modules must export anything that should be available to code outside of the module.
- Modules may import bindings from other modules.
JavaScript ES6 & Typescript
Export
// Data
export var color = "red";
export let person = { name : "Andrei" };
export const value = 7;
// Functions
export function sum(num1, num2) {
return num1 + num1;
}
// Classes
export class Rectangle {
constructor(length, width) {
this.length = length;
this.width = width;
}
}
JavaScript ES6 & Typescript
Export references
// this function is private to the module
function subtract(num1, num2) {
return num1 - num2;
}
function multiply(num1, num2) {
return num1 * num2;
}
export { multiply };
JavaScript ES6 & Typescript
Import
// Single binding
import { sum } from "./example.js";
console.log(sum(1, 2)); // 3
sum = 1; // error
// Multiple bindings
import { sum, multiply, number } from "./example.js";
console.log(sum(1, number)); // 8
console.log(multiply(1, 2)); // 2
// All module
import * as example from "./example.js";
console.log(example.sum(1, example.number)); // 8
console.log(example.multiply(1, 2)); // 2
JavaScript ES6 & Typescript
Import
// module gets executed only once
import { sum } from "./example.js";
import { multiply } from "./example.js";
import { number } from "./example.js";
module gets executed only once
JavaScript ES6 & Typescript
Import
if (flag) {
export flag; // syntax error
}
function tryImport() {
import flag from "./example.js"; // syntax error
}
imports / exports cannot be done in statements
JavaScript ES6 & Typescript
Import / Export
// source.example.js
export var name = "John";
export function setName(newName) {
name = newName;
}
// dest.example.js
import { name, setName } from "./source.example.js";
console.log(name); // "John"
setName("Jane");
console.log(name); // "Jane"
name = "Joe"; // error
cannot modify import bindings
JavaScript ES6 & Typescript
Import / Export
// exports
function sum(num1, num2) {
return num1 + num2;
}
export { sum as add };
// imports
import { add as sum } from "./example.js";
console.log(typeof add); // "undefined"
console.log(sum(1, 2)); // 3
imports / exports can be renamed
JavaScript ES6 & Typescript
Import / Export
// option 1
// export
export default function(num1, num2) {
return num1 + num2;
}
// import
import sum from "./example.js";
console.log(sum(1, 2)); // 3
// option 2
// export
function sum(num1, num2) {
return num1 + num2;
}
export { sum as default };
// import
import sum from "./example.js";
console.log(sum(1, 2)); // 3
// option 3
// export
export let color = "red";
export default function(num1, num2) {
return num1 + num2;
}
// import
import sum, { color } from "./example.js";
console.log(sum(1, 2)); // 3
console.log(color); // "red"
you can export / import as default
JavaScript ES6 & Typescript
Import / Export
// export
// example.js
Array.prototype.pushAll = function(items) {
// items must be an array
if (!Array.isArray(items)) {
throw new TypeError("Argument must be an array.");
}
// use built-in push() and spread operator
return this.push(...items);
};
// import
import "./example.js";
let colors = ["red", "green", "blue"];
let items = [];
items.pushAll(colors);
you can import without use of bindings
JavaScript ES6 & Typescript
Import / Export
<!-- load a module JavaScript file -->
<script type="module" src="module.js"></script>
<!-- include a module inline -->
<script type="module">
import { sum } from "./example.js";
let result = sum(1, 2);
</script>
importing in web browsers
Iterators
JavaScript ES6 & Typescript
JavaScript ES6 & Typescript
var colors = ["red", "green", "blue"];
for (var i = 0, len = colors.length; i < len; i++) {
console.log(colors[i]);
}
For loop
Tend to get complicated when complex logic and nesting is required
JavaScript ES6 & Typescript
function createIterator(items) {
var i = 0;
return {
next: function() {
var done = (i >= items.length);
var value = !done ? items[i++] : undefined;
return {
done: done,
value: value
};
}
};
}
var iterator = createIterator([1, 2, 3]);
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next()); // "{ value: 2, done: false }"
console.log(iterator.next()); // "{ value: 3, done: false }"
console.log(iterator.next()); // "{ value: undefined, done: true }"
// for all further calls
console.log(iterator.next()); // "{ value: undefined, done: true }"
Iterators
JavaScript ES6 & Typescript
// generator
function *createIterator() {
yield 1;
yield 2;
yield 3;
}
// generators are called like regular functions but return an iterator
let iterator = createIterator();
console.log(iterator.next().value); // 1
console.log(iterator.next().value); // 2
console.log(iterator.next().value); // 3
// for all further calls
console.log(iterator.next().value); // undefined
Generators
functions that return an iterator
JavaScript ES6 & Typescript
- The * before the function name makes the function a generator.
Key characteristics
- The yield keyword specifies values the resulting iterator should return when next() is called
JavaScript ES6 & Typescript
// iterator as a function
let createIterator = function *(items) {
for (let i = 0; i < items.length; i++) {
yield items[i];
}
};
let iterator = createIterator([1, 2, 3]);
// iterator inside object
var o = {
createIterator: function *(items) {
for (let i = 0; i < items.length; i++) {
yield items[i];
}
}
};
let iterator = o.createIterator([1, 2, 3]);
Creating an arrow function that is also a generator is not possible.
Generators
JavaScript ES6 & Typescript
// example 1
let values = [1, 2, 3];
for (let num of values) {
console.log(num);
}
// 1
// 2
// 3
// example 2
let divs = document.getElementsByTagName("div"); // NodeList Iterator
for (let div of divs) {
console.log(div.id);
}
for...of iterator
JavaScript ES6 & Typescript
- A for-of loop calls next() on an iterable
- A for-of loop first calls the Symbol.iterator method on the values array to retrieve an iterator.
- The for-of statement will throw an error when used on, a non-iterable object, null, or undefined.
JavaScript ES6 & Typescript
Accessing the default iterator
let values = [1, 2, 3];
let iterator = values[Symbol.iterator]();
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next()); // "{ value: 2, done: false }"
console.log(iterator.next()); // "{ value: 3, done: false }"
console.log(iterator.next()); // "{ value: undefined, done: true }"
JavaScript ES6 & Typescript
Detecting if an object is iterable
function isIterable(object) {
return typeof object[Symbol.iterator] === "function";
}
console.log(isIterable([1, 2, 3])); // true
console.log(isIterable("Hello")); // true
console.log(isIterable(new Map())); // true
console.log(isIterable(new Set())); // true
console.log(isIterable(new WeakMap())); // false
console.log(isIterable(new WeakSet())); // false
JavaScript ES6 & Typescript
Creating iterables
let collection = {
items: [],
*[Symbol.iterator]() {
for (let item of this.items) {
yield item;
}
}
};
collection.items.push(1);
collection.items.push(2);
collection.items.push(3);
for (let x of collection) {
console.log(x);
}
// 1
// 2
// 3
JavaScript ES6 & Typescript
Passing arguments to iterators
function *createIterator() {
let first = yield 1;
let second = yield first + 2; // 4 + 2
yield second + 3; // 5 + 3
}
let iterator = createIterator();
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next(4)); // "{ value: 6, done: false }"
console.log(iterator.next(5)); // "{ value: 8, done: false }"
console.log(iterator.next()); // "{ value: undefined, done: true }"
JavaScript ES6 & Typescript
Throwing error in iterators
function *createIterator() {
let first = yield 1;
let second = yield first + 2; // yield 4 + 2, then throw
yield second + 3; // never is executed
}
let iterator = createIterator();
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next(4)); // "{ value: 6, done: false }"
console.log(iterator.throw(new Error("Boom"))); // error thrown from generator
JavaScript ES6 & Typescript
Generator return value
// return without value
function *createIterator() {
yield 1;
return;
yield 2;
yield 3;
}
let iterator = createIterator();
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next()); // "{ value: undefined, done: true }"
// return with value
function *createIterator() {
yield 1;
return 42;
}
let iterator = createIterator();
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next()); // "{ value: 42, done: true }"
console.log(iterator.next()); // "{ value: undefined, done: true }"
Async / Await
JavaScript ES6 & Typescript
JavaScript ES6 & Typescript
async function getName() {
const url = 'https://jsonplaceholder.typicode.com/';
let response = await fetch(`${url}posts/-1`);
const post = await response.json();
const userId = post.userId;
response = await fetch(`${url}users/${userId}`);
const user = await response.json();
return user.name;
}
getName()
.then(name => console.log(name))
.catch(error => console.log('error'));
JavaScript ES6 & Typescript
- Any function can be async
- Awaiting async can only be done in async context
- Async functions return a promise
Typescript Overview
JavaScript ES6 & Typescript
JavaScript ES6 & Typescript
- Superset of ECMAScript
- Open Source
- Anders Hejlsberg @ Microsoft, 2012
JavaScript ES6 & Typescript
How does it work?
Type System
JavaScript ES6 & Typescript
JavaScript ES6 & Typescript
let animal; // declares only a value
interface Mamal {} // declares a type
class Dog {} // declares a value and a type
Values end up in resulting JavaScript, types don't
JavaScript ES6 & Typescript
interface Person {
age: number;
}
class John implements Person {
constructor(public age: number) {}
}
let pers1: Person = new John(32);
let pers2: John = {age: 32};
Structural typing
Classes
JavaScript ES6 & Typescript
JavaScript ES6 & Typescript
We can use types in classes
Same as ES6 classes
Interfaces
JavaScript ES6 & Typescript
JavaScript ES6 & Typescript
interface Node {
(x: string): string; // callable
new (label: string): Node; // constructor
children: Node[]; // property
numChildren(): number; // method
}
All types are expressible as interfaces
JavaScript ES6 & Typescript
interface Data {
[key: string]: boolean;
}
const d: Data = {};
d['key1'] = true;
console.log(d['key1']); // true
Interfaces allow for typing object index signature
Union / Intersection types
JavaScript ES6 & Typescript
JavaScript ES6 & Typescript
type primitive = string | number | boolean;
type object = String | Number | Boolean;
type dataType = primitive | object;
Union
JavaScript ES6 & Typescript
type MyDiv = HTMLDivElement & {customDivAttr: string};
Intersection
JavaScript ES6 & Typescript
type el = HTMLAnchorElement | HTMLImageElement;
const location = (d: el) => {
if(d instanceof HTMLAnchorElement) {
return d.href;
}
return d.src;
}
Usage: narrows casting
JavaScript ES6 & Typescript
function one(x: string | undefined) { ... }
one();
// Error: requires one argument
function two(x?: string) { ... }
two();
// It's ok
Optional arguments
Enums
JavaScript ES6 & Typescript
JavaScript ES6 & Typescript
enum Card {
CLUBS = 1, // Subsequent values are incrm. from 1
DIAMONDS,
HEARTS,
SPADES
}
enum Colors {
RED = '#FF0000',
GREEN = '#00FF00',
BLUE = '#0000FF'
}
let myCard = Card.HEARTS; // 3
let red = Colors.RED; // #FF0000
Enums assign a numbers/strings to each symbol
Generics
JavaScript ES6 & Typescript
JavaScript ES6 & Typescript
class GenericQueue<T> {
enqueue(value: T) : void {/*enqueue value */}
dequeue() : T {/*dequeue value*/}
}
let q2 = new GenericQueue<string>();
q2.enqueue("Hello");
q2.enqueue(17); // compilation error
let q3 = new GenericQueue<Animal>();
q3.enqueue(new Animal("Max"));
q3.enqueue("Hello"); // compilation error
Decorators
JavaScript ES6 & Typescript
JavaScript ES6 & Typescript
function ClassDecoratorParams(param1: number, param2: string) {
return function(
target: Function // The class the decorator is declared on
) {
console.log("ClassDecoratorParams(" + param1 + ", '" +
param2 + "') called on: ", target);
}
}
@ClassDecoratorParams(1, "a")
@ClassDecoratorParams(2, "b")
class ClassDecoratorParamsExample {
}
// ClassDecoratorParams(2, 'b') called on: function ClassDecoratorParamsExample() {}
// ClassDecoratorParams(1, 'a') called on: function ClassDecoratorParamsExample() {}
Functions that are invoked with a prefixed @ symbol, and immediately followed by a class, parameter, method or property.
Q&A
JavaScript ES6 & Typescript
Thank you!
JavaScript ES6 & Typescript
By Alex Albu
JavaScript ES6 & Typescript
- 453