Slide 1

Slide 1 text

A type system in plain javascript @lilobase lgo.group My twitter

Slide 2

Slide 2 text

What’s the type ? const count_word = string => string.split(" ").length;

Slide 3

Slide 3 text

A function is defined by its domain & co-domain function Domain Co- Domain

Slide 4

Slide 4 text

A function is defined by its domain & co-domain String Integer count_word

Slide 5

Slide 5 text

A function’s domain & codomain are sets String Integer count_word Set of all Strings Set of all Integers

Slide 6

Slide 6 text

Knowing about domain & co-domain leads to a massive advantage Check correctness Int count_word

Slide 7

Slide 7 text

Enables safe composition f g h h = g•f Knowing about domain & co-domain leads to a massive advantage

Slide 8

Slide 8 text

Adapts behavior f { } This is « pattern matching » Knowing about domain & co-domain leads to a massive advantage

Slide 9

Slide 9 text

Types can be considered as « Sets »

Slide 10

Slide 10 text

How do we check types ? const count_word = string => { if(typeof string !== 'string') 
 throw new TypeError;
 return string.split(" ").length; }

Slide 11

Slide 11 text

How can we define a set ? using a predicate : 
 - is x a member of E

Slide 12

Slide 12 text

How do we check types ? const assert = predicate => value => { if(!predicate(value)) throw new TypeError; } const count_word = string => { assert(e => typeof e === 'string')(string); return string.split(" ").length; }

Slide 13

Slide 13 text

How do we check types ? const assert = predicate => value => { if(!predicate(value)) throw new TypeError; } const Str = assert(e => typeof e === 'string'); const count_word = string => { Str(string); return string.split(" ").length; }

Slide 14

Slide 14 text

How can we create a set ? using a constructor : - put x in E if x can be a member of E

Slide 15

Slide 15 text

How do we check types ? const assert = predicate => value => { if(!predicate(value)) throw new TypeError; } const Str = value => { assert(e => typeof e === 'string')(value); return value; }; const count_word = 
 string => string.split(" ").length; const typed_count_word = 
 value => count_word(Str(value));

Slide 16

Slide 16 text

Type refinement Integer count_word

Slide 17

Slide 17 text

Type refinement Positive Integer count_word

Slide 18

Slide 18 text

Type refinement Positive Integer Integer

Slide 19

Slide 19 text

Type refinement const Int = value => { assert(e => e === parseInt(e, 10) && !isNaN(e) )(value); return value; }

Slide 20

Slide 20 text

Let’s create a type constructor const Type = predicate => value => { assert(predicate)(value); return value; } const Int = Type(
 e => e === parseInt(e, 10) && !isNaN(e)
 );

Slide 21

Slide 21 text

Type refinement const Int = Type(
 e => e === parseInt(e, 10) && !isNaN(e)
 ); const refinement = (type, predicate) => value =>
 Type(predicate)(type(value)); const PositiveInt = refinement(Int, e => e > 0);

Slide 22

Slide 22 text

What’s the type ? const count_each_word = string => 
 string.split(" ").reduce( (acc, item) => { acc[item] = (acc[item] || 0) + 1; return acc; } , {});

Slide 23

Slide 23 text

What’s the the type ? String ? count_each_word

Slide 24

Slide 24 text

Type combinator String count_each_word Dictionary : 
 String -> Int

Slide 25

Slide 25 text

Type combinator const dict = (domain, codomain) => values => { Object.entries(values)
 .forEach(([key, value]) => { domain(key); codomain(value); }); return values; }; const Phonebook = dict(Str, Int); const phonebook = Phonebook({ 'Andrew Parson': 8806336, 'Emily Everett': 6784346 });

Slide 26

Slide 26 text

You don’t need to code it yourself tcomb github.com/gcanti/tcomb/

Slide 27

Slide 27 text

Enums const Vegetable = t.enums.of([ 'Tomato', 'Onion', 'Salad' ], 'Vegetable'); const Meat = t.enums.of([ 'Mutton' ], 'Meat'); const SeaFood = t.enums.of([ 'Shrimp', 'Fish' ], 'SeaFood');

Slide 28

Slide 28 text

Type union const Ingredient = t.union([
 Vegetable, 
 Meat, 
 SeaFood ], 'Ingredient');

Slide 29

Slide 29 text

Struct (& list) const Ingredient = t.union([
 Vegetable, 
 Meat, 
 SeaFood ], 'Ingredient');
 
 const Kebab = t.struct({ ingredients: t.list(Ingredient), }, 'Kebab');

Slide 30

Slide 30 text

Typed function const Vegetable = t.enums.of([ 'Tomato', 'Onion', 'Salad' ], 'Vegetable'); const Kebab = t.struct({ ingredients: t.list(Ingredient), }, 'Kebab'); 
 const isVegetarian = t.func([Kebab], t.Boolean).of(
 ({ingredients}) => ingredients.every(Vegetable.is) ); Type definition Our function

Slide 31

Slide 31 text

Sub-typing (refinement) const isVegetarian = t.func([Kebab], t.Boolean).of(
 ({ingredients}) => ingredients.every(Vegetable.is) ); 
 const VeggieKebab = t.refinement(Kebab, isVegetarian, 'VegetarianKebab');

Slide 32

Slide 32 text

Is my kebab vegetarian ? const kebab = Kebab(['Tomato', 'Salad']); VegetarianKebab.is(kebab);

Slide 33

Slide 33 text

Type safety const veggiKebab = VegetarianKebab([ 'Tomato', 'Salad' ]);

Slide 34

Slide 34 text

And many other • Dictionary • Tuple • Recursive types • Maybe • Intersection • Interface • …

Slide 35

Slide 35 text

And, they are available at runtime…

Slide 36

Slide 36 text

Payload validation import fromJSON from 'tcomb/lib/fromJSON'; axios .get('/api/kebab/veggie/5') .then(({data}) => 
 fromJSON(data, VegetarianKebab));

Slide 37

Slide 37 text

Pattern matching const result = t.match(myCurrentKebab, //do something if the kebab is vegetarian VegetarianKebab, (kebab) => ... , //do something else for all other kebab Kebab, (kebab) => ... , //this is definitely not a kebab t.Any, (x) => ... ); The value to match against Type to match Function to execute if the associated type is matched

Slide 38

Slide 38 text

Forms (with react) this.form = form} type={Kebab} value={values} />

Slide 39

Slide 39 text

Take away • Types are not data nor behavior
 they can be seen as sets • There is a set algebra we can use to combine types
 (algebraic typing) • Use tComb 
 (we do it, everyday, on all production projets) • And, moreover, it enables a better domain representation

Slide 40

Slide 40 text

Thanks ! @lilobase lgo.group a fair, secure by design & transparent exchange