Tomasz Ducin

JavaScript + Java
= TypeScript

Tomasz Ducin

22nd April 2017, Warsaw

JavaScript + Java
= TypeScript

Tomasz Ducin

14th February 2017, Warsaw

#11

JavaScript + Java
= TypeScript

Tomasz Ducin

8th February 2017, Warsaw

JavaScript + C#
= TypeScript

Tomasz Ducin

31st January 2017, Warsaw

#196

JavaScript + Java
= TypeScript

Tomasz Ducin

30th September 2016, Warsaw

JavaScript + Java
= TypeScript

Tomasz Ducin

23rd September 2016, Praha

JavaScript + Java
= TypeScript

Tomasz Ducin

8th September 2016, Warsaw

You don't know TS

Tomasz Ducin

15th June 2016, Darmstadt

JavaScript + Java
= TypeScript

JavaScript + Java = TypeScript

Tomasz Ducin

8th June 2016, Warsaw

#22

Tomasz Ducin

23rd April 2016, Szczecin

JavaScript + Java
= TypeScript

Tomasz Ducin

11th April 2016, Warsaw

JavaScript + Java
= TypeScript

Tomasz Ducin

JavaScript, Java, Python

software developer @ Ivanti

trainer @ Bottega IT Solutions

blah, blah, blah...

Agenda

  1. a glance at TS
  2. JS tooling landscape
  3. TypeScript - and tech problems:
    solved & unsolved
  4. JS, ES6, TS, CS... & flow
  5. TS: profit and loss

TypeScript

experienced?

Are you

  • private customer banking interface
  • TypeScript-based 
  • 1+ year to go on production
  • deployed on 120+ Scandinavian banks

Retail Banking

  • massive fake data generator
  • based on:
    • JSON Schema
    • faker.js, chance.js
  • started in 2014
  • rewritten to TS in 2016, v0.3

TypeScript

  • typed superset of JavaScript 

function objectRange(obj, times) {
  ...
}
function objectRange(obj: Object, times: number) {
  ...
}
function objectRange(obj: Object, times: number): Object[] {
  ...
}
module myModule {
  function objectRange(obj: Object, times: number): Object[] {
    ...
  }
  ...
}
  • new language, transpiled to JS

  • classes, interfaces, modules, generics
    - inherited from Java/.Net

  • runtime & compile-time

  • maintained by Microsoft & Google

module myModule {
  interface Person {
    name: string;
    age: number;
  }

  class MyClass {
    private varA: typeA;

    constructor(varB: typeB) {...}

    public objectRange(obj: Object, times: number): Object[] {
      ...
    }
  }
  ...
}
function objectRange<T>(obj: T, times: number): T[] {
	var result: T[] = [];
	for (var i = 0; i < times; i++) {
		result.push(obj);
	}
	return result;
}
module cash {	
	export interface Payment {
		amount: number;
		account: string;
	}
}
var payments = objectRange<cash.Payment>({
    "amount":12.34,
    "account": "1234 5678 90"
}, 5);

console.log(payments);
function objectRange<T>(obj: T, times: number): T[];
module cash {	
	export interface Payment {
		amount: number;
		account: string;
	}
}
  • weak typing
  • strong typing

TypeScript

  • weak typing
  • asynchronous,
    single-threaded
  • functional
    programming
  • both clients and servers
  • object oriented programming
  • class-based

=

  • asynchronous,
    single-threaded
  • functional
    programming
  • both clients and servers
  • prototype-based
  • class-based
  • synchronous/parallel mainly
  • object oriented programming
  • server-side
  • dynamic typing
  • static typing
  • static typing

JavaScript

Java

+

JavaScript Fatigue

x

x

x

x

cool kids fighting
for their frameworks

think about the problems you solve,
NOT the tools

~98% aware of TS existence

~72% doesn't know TS / only ~28% does

~53% interested in learning / ~47% not

~85% satisfaction with TS

just what I wanted to say is,  please try not introduce new technologies and thereby complexities without having a good reason to do so... For now we have a lot to cope with, So if you guys keep racing then we don't have a chance to get somehow on the same boat.

a colleague from my project

why should I use       ?

  • because I've got classes!

  • because I've got types!

  • because I shift some responsibility onto the platform!

 the purpose of a programming language is to aid programmers in producing error-free programs

problems TS 

 solves

1. checks types

test.ts(5,5): error TS2345: Argument of type 'string'
  is not assignable to parameter of type 'number'.

type time

!!!

Primitive types

string

number

boolean

var a: boolean;
let f = false;
const t: boolean = true;
var a: number = 5;
let b: number;
const c = 20;
var a: string = 'John';
let name: string = `${a}`;
const c = "training";

array

var boolList: Array<boolean>
let boolList: boolean[]
const cList: boolean[] = [];
cList.push(true);

same const as ES6

Function types

function fullName(first, last) {
  return first + ' ' + last;
}
function fullName(first, last): string {
  return first + ' ' + last;
}
function fullName(first: string, last: string) {
  return first + ' ' + last;
}
function fullName(first: string, last: string): string {
  return first + ' ' + last;
}

nowhere

return

params

both

type Oper = (a: number, b: number) => number;

const add: Oper = (a, b) => a + b;
const sub: Oper = (a, b) => a - b;
const mul: Oper = (a, b) => a * b;
const div: Oper = (a, b) => a / b;
 get(url: string,
     data?: Object|string,
     success?: (data: any, textStatus: string, jqXHR: JQueryXHR) => any,
     dataType?: string
    ): JQueryXHR

priceless for defining callbacks

jQuery.get(...) type

Function types

interface Person {
  first: string;
  last: string;
}
interface Person {
  first: string; // required
  last: string; // required
  age?: number; // optional
}
interface Address {
  city: string;
  country: string;
  postcode?: string;
}
interface Person {
  first: string; // required
  last: string; // required
  age?: number; // optional
  addresses: Address[];
}

C-style structs

contracts

Interfaces

type Currency =
  "EUR" | "GBP" | "USD" | "AUD" | "CAD";
type Season =
  "spring" | "summer" | "autumn" | "winter";

typedefs

let currentSeason: Season = "autumn"
currentSeason = "cucumber" // ERROR

String literal types

Tuples

type Currency =
  "EUR" | "GBP" | "USD" | "AUD" | "CAD" | "NZD"
type MoneyTuple = [number, string]
let m: MoneyTuple = [4.99, "EUR"]
type MoneyTuple = [number, Currency]
let m1: MoneyTuple = [4.99, "EUR"]
let m2: MoneyTuple = [4.99, "PLN"] // ERROR

non-string enumerables

enum Directions {
    Up, Down, Left, Right
}
lets moves: Directions[] = [
  Directions.Right
  Directions.Up,
  Directions.Right
  Directions.Left,
  Directions.Up,
  Directions.Up,
  Directions.Up,
  Directions.Left,
  Directions.Down,
  Directions.Up,
  Directions.Left,
  Directions.Down,
];

C-style enums

Enums

interface IPerson {
  firstName: string,
  lastName: string
}

type PersonString = string

type PersonTuple = [string, string]
type UberPerson = IPerson
  | PersonString
  | PersonTuple
function greet(person: UberPerson) {...}

greet("John Lennon")
greet(["John", "Lennon"])
greet(["John", "Lennon", 40]) // ERROR
greet({ firstName: "John", lastName: "Lennon" })
greet({ firstName: "John", lastName: "Lennon", age: 40 }) // ERROR

Unions

Intersections

interface Person {
    first: string;
    last: string;
    age?: number;
}
interface Citizen {
    regNo: string;
    bankAccount: string;
}
const john: Person & Citizen = {
  first: "John",
  last: "Lennon",
  regNo: "957204578204",
  bankAccount: "94 9834 0956 1238 5499"
}

problems TS 

  solves

3. less unit tests

assert.isString
assert.isNumber
assert.isBoolean

problem exists in all weakly-typed languages

2. less runtime bugs

problems TS 

  solves

4. self-documenting

interface AccountingSummary {
  id: string;
  items: AccoutningItem[];
  price: Amount;
  signedBy?: Employee;
  submittedBy?: Employee;
}

class Department {
  public generateSummary(...): AccountingSummary {
    ... // long method
  };
  ...
}

problems TS 

  solves

5. type inference

let foo = 123;
let bar = "Hello";
let foo = 123; // foo is a `number`
let bar = "Hello"; // bar is a `string`

foo = bar;
    // Error: cannot assign
    // `string` to a `number`
let foo = 123; // foo is a `number`
let bar = "Hello"; // bar is a `string`

problems TS 

  solves

6. reduces JS pitfalls

// JS
var a = 4;
var b = 5;
var c = a * b;
// c == 20
// JS
var a = "hello";
var b = "world";
var c = a * b;
// c == NaN
// TS
var a: string = "hello";
var b: string = "world";
var c: string = a * b;
// TS
var a = "hello";
var b = "world";
var c = a * b;
test.ts(4,5): error TS2322: Type 'number' is not assignable to
  type 'string'.
test.ts(4,17): error TS2362: The left-hand side of an arithmetic
  operation must be of type 'any', 'number' or an enum type.
test.ts(4,21): error TS2363: The right-hand side of an arithmetic
  operation must be of type 'any', 'number' or an enum type.

problems TS 

  solves

7. disables JS hacks

var mod = null;

function logic(){
  ... use `mod` here
}

module.exports = function(){
  mod = mod || require('MODULE');
  return logic.apply(...);
}

?

var mod = require('MODULE');

module.exports = function logic(){
  ... use `mod` here
}

problems TS 

  solves

8. native modules

module outer {
  var str = "hello world";
  module inner {
    var num = 6;
  }
}
var outer;
(function (outer) {
    var str = "hello world";
    var inner;
    (function (inner) {
        var num = 6;
    })(inner || (inner = {}));
})(outer || (outer = {}));

problems TS 

  solves

9. big business logic under control

Design Patterns

Domain Driven Design

class ThatDoesSomething {
    public mainPromise: ng.IPromise<IUser[]>;
    public users: IUser[];

    private fetchUsers(): ng.IPromise<IUser[]> {
      return UserModel.getUsers(params)
        .then((response: IUser[]) => {
          this.users = response;
        });
    }

    public $onInit(): void {
      this.mainPromise = this.fetchUsers();
    }
}

Typed Promises

class UserModel {
    public getUsers(params: ...): ng.IPromise<IUser[]> {
      return Restangular.get('users');
    }
}
var promise = Promise(); // of what ???

promise.then(function(???){
  data = ???
})

Low-level Refactoring

CORE

M1

M2

M3

change or extend

var price = 7.99;
var price = {
  amount: 7.99,
  currency: "PLN"
};

Value Objects

declare type Price = number;

interface Price {
  amount: number;
}
interface Price {
  amount: number;
  currency: string;
}

Communication Contract

Data Transfer Objects

// GET /customers/{id}
interface Customer {
  firstName: string;
  lastName: string;
  age: number;
}

Data Transfer Objects

Data Transfer Objects

// GET /customers
// GET /customers/{id}
interface Customer {
  firstName: string;
  lastName: string;
  age: number;
}
declare type CustomerList = Customer[];

Data Transfer Objects

// GET /customers
// GET /customers/{id}
// GET /customers/{id}/addresses
interface Address {
  street: string;
  city: string;
  country: string;
}
interface Customer {
  ...
  addresses: Address[];
}

Data Transfer Objects

getAsyncData({
  url: "/customers/<id>"
  method: "GET",
  ...
}, function(customer: Customer): void {
  process(customer.firstName); // ok
  process(customer.lastName); // ok
  process(customer.name); // ERROR!!!
});

problems TS

 doesn't solve

1. mistakes

  • logical mistakes
  • lack of knowledge
  • asynchronous errors
    (e.g. race conditions)

problems TS

 doesn't solve

2. still need to understand JS

  • writing TS without knowing JS == disaster
  • what output will TS provide?
  • read code in terms of both: OOP and async runtime

problems TS

 doesn't solve

3. won't make it faster

  • won't make you code faster
  • won't make app run faster
  • actually, will slow both down just a little bit
  • TS might produce more code than pure JS (modules, classes)

problems TS

 doesn't solve

4. the any type

  • stands for NO TYPE
  • very easy to use
  • very messy to use
  • it's very tempting
  • sometimes just can't do without
  • will spoil your app if used in big amounts
  • just like donuts...
var a: any = ... // EXPLICIT any

// a - INFERRED
// b - IMPLICIT any
function doSomething(a, b){
  a.push(b);
}

nothing comes for free

problems TS

introduces

1. automation becomes
more expensive

  • need to transpile TS down to JS
  • big project = big cost
  • blockers included

problems TS

introduces

2. compatibility with
3rd party libs

  • DefinitelyTyped
  • less popular projects lack .d.ts files

problems TS

introduces

3. your teammates need to learn

  • probably you'll teach them
  • entry level is quite low

problems TS

introduces

4. debugging less convenient

  • browsers don't execute TS
  • source and output: different

problems TS

introduces

automation
more expensive

3rd party libs compatibility

teach people

debugging less convenient

writing JavaScript is not trendy anymore

JS vs ES6 vs TS

writing TypeScript is not trendy anymore

choose TypeScript for development of any new project

when is it worth to go TS?

project?

people?

  • size, codebase
  • domain complexity
  • open for changes
  • non-dogmatic attitude

technical dogma example

JavaScript shall always remain dynamically typed

all decisions have pros and cons

transpiling JS

pros & cons

  • more features
  • might be less code
  • efficiency
  • following trends
  • more code complexity
  • higher entry-level
    for BE & junior devs
  • IDE support needed
  • more setup complex

value of the new features

costs of introducing it

>

?

think about the problems you solve, NOT the tools

always be responsible for the tools you introduce

nothing comes for free

all decisions have pros and cons

THX!

4  Q&A

writing JavaScript is not trendy anymore ;)

ES6

TypeScript

  • most of what ES6 has
  • type checks

  • templates typecheck
    ( ongoing)
  • TS -> ES6 (ongoing)

CoffeeScript syntax

# Assignment:
number   = 42
opposite = true

# Conditions:
number = -42 if opposite

# Functions:
square = (x) -> x * x

# Arrays:
list = [1, 2, 3, 4, 5]
var list, number, opposite, square;

number = 42;

opposite = true;

if (opposite) {
  number = -42;
}

square = function(x) {
  return x * x;
};

list = [1, 2, 3, 4, 5];

CoffeeScript syntax

# Splats:
race = (winner, runners...) ->
  print winner, runners
var race,
  slice = [].slice;

race = function() {
  var runners, winner;
  winner = arguments[0],
    runners = 2 <= arguments.length ?
      slice.call(arguments, 1) : [];
  return print(winner, runners);
};

CoffeeScript usecase

class DataWidgetCtrl

  fetchData: ->
    @$timeout =>
      @table.loaded = true
      resourceObject = angular.fromJson(@$attrs.resource)
      model = @$injector.get(resourceObject.model)
      @table.promise = model[resourceObject.method](resourceObject.id).then (res) =>
        @setData(res)
        @init()
      , (res) =>
        @getHeader(@def.i18n, @table)
        @table.error = res.status
    , 0

...
var DataWidgetCtrl;

DataWidgetCtrl = (function() {

  DataWidgetCtrl.prototype.fetchData = function() {
    return this.$timeout((function(_this) {
      return function() {
        var model, resourceObject;
        _this.table.loaded = true;
        resourceObject = angular.fromJson(_this.$attrs.resource);
        model = _this.$injector.get(resourceObject.model);
        return _this.table.promise = model[resourceObject.method]
         (resourceObject.id).then(function(res) {
          _this.setData(res);
          return _this.init();
        }, function(res) {
          _this.getHeader(_this.def.i18n, _this.table);
          return _this.table.error = res.status;
        });
      };
    })(this), 0);
  };

...

  return DataWidgetCtrl;

})();

writing JavaScript is not trendy anymore ;)