ES2018 and beyond

Milano JS Logo

Milan - 2018-05-16

maxart2501.github.io/es2018-and-beyond-talk/

Massimo Artizzu

GitHub logo / Twitter logo @MaxArt2501
Slack logo maxart

Antreem logo

ES2015 was fantastic

ES2016 was… meh.

ES2017 had some meat again

And this is ES2018:

We already know and ❤️:

const settings = {
  ...defaultSettings,
  ...userSettings
}
transform-object-rest-spread

This should be clear:

someAsyncStuff()
  .then(dealWithResult)
  .catch(handleMess)
  .finally(cleanUp)
promise.prototype.finally

for await...of
or better: asynchronous generators

async function* spillButChill() {
  for (const thing of list)
    yield thing
}
transform-async-generator-functions

Iterator's next() method returns a Promise:

const iterable = spillButChill()
const iterator = iterable[Symbol.asyncIterator]
iterator.next()
  .then(thing => { /*...*/ })

A use case w/ Node 10

const stream = fs.createReadStream(filepath)
let size = 0
for await (const chunk of stream) {
  size += chunk.length
}
console.log('File size:', size)

New stuff for regexes!

I.e.: new ways to make two problems out of one

dotAll

/./.test('\n')  // 👎
/./s.test('\n') // 👍
transform-dotall-regex

Named captures

const re = /^(?<protocol>https?):/
const match = re.exec(url)
console.log(match.groups.protocol)

Lookbehinds

Check if something comes before:

const re = /(?<=\. )[a-z]/g
title = title.replace
    (re, i => i.toUpperCase())

Unicode escapes

Syntax: \p{category_name=set_name}

Use \P to not include the set.

const greek = /^\p{Script=Greek}+$/
console.log(greek.test('μετά')) // 👍

So… what's waiting for us?

🔭

Proposal stages 🚀

import() 🚀3

const module = `./components/${type}.js`;
const Component = await import(module)
return <Component>Hello!</Component>
syntax-dynamic-import

Private fields/methods/accessors 🚀3

class Meh {
  #w;
  #h;
  get #area() { return this.#w * this.#h }
  #init() {
    this.#w = 1;
    this.#h = 1;
  }
  constructor() { this.#init() }
}

We reserved the private keyword for nothing… 😠

Array::flatMap
Array::flatten smoosh flat 🚀3

[1, 2].flatMap(n => [n, n*n]) // [1, 1, 2, 4]

const array = [1, [2, 3], [[4]]]
array.flat()                // [1, 2, 3, [4]]
array.flat(Infinity)        // [1, 2, 3, 4]

Static class fields/methods 🚀2

class Covfefe extends React.Component {
  static defaultProps = { wtf: 9001 }
  static getRandom(max = 10000) {
    const wtf = Math.floor(Math.random(max))
    return <Covfefe wtf={wtf}/>
  }
}
transform-class-properties

Decorators 🚀2

@defineElement('date-picker')
class DatePicker extends HTMLElement {
  @readonly
  today = new Date();

  @bound
  clickHandler() {
    // ...
  }
}

Decorators are functions

function bound(methodDescriptor) {
  return {
    ...methodDescriptor,
    extras: [{ /* bound method descriptor */ }]
  }
}
transform-decorators

Observables 🚀1

A-la RxJS 5:

function fromEvent(el, evName) {
  return new Observable(observer => {
    const handler = event => observer.next(event)
    el.addEventListener(evName, handler)
    return () => el.removeEventListener(evName, handler)
  });
}
fromEvent(theInput, 'keydown')
  .filter(({ key }) => key === 'Escape')
  .subscribe(() => theInput.value = '')

Optional chaining 🚀1

const street = address ? address.street : undefined
// becomes...
const street = address?.street

// Also for optional methods:
user.resetPassword?.()
@babel/plugin-syntax-optional-chaining

do expressions 🚀1

Basically, a more compact IIFE:

function Header({ isLogged }) {
  return <header>{ do {
    if (isLogged) <LogoutButton />
    else <LoginButton />
  }}</header>
}
transform-do-expressions

Partial applications 🚀1

const powerOf2 = Math.pow.bind(null, 2)
const square = n => n ** 2

now become:

const powerOf2 = Math.pow(2, ?)
const square = Math.pow(?, 2)

Pipelines 🚀1

Two factions are fighting:

F# pipelines

const coords = await resolveCoords(
  (await (await fetch(`/api/${entity}`)).json()).user.location
)

now becomes:

const coords = `/api/${entity}`
  |> fetch
  |> await
  |> resp => resp.json()
  |> await
  |> data => data.user.location
  |> resolveCoords
  |> await

Smart pipelines

F# pipelines + partial applications?

const coords = `/api/${entity}`
  |> fetch
  |> await #
  |> #.json()
  |> await #
  |> #.user.location
  |> resolveCoords
  |> await #

That's all, folks!
maxart2501.github.io/es2018-and-beyond-talk/