Jim Cheung

(reading notes on Introducing Deno: A First Look at the Newest JavaScript Runtime)

2. An Introduction to TypeScript

declaring arrays

let variable : number[] = [1,2,34,45]

// another way
let variable : Array<number>  = [1,2,3,4]

new types

tuples

tuples allow you to predefine a limited number of elements, but you can pick their type

let myTuple: [string, string] = ["hello", "world!"]
let myTuple2: [string, number] = ["hello", 1]
let myList: [number, string][] = [[1, "Steve"], [2, "Bill"], [3, "Jeff"]]
myList.push([4, "New Name"])

enums

enum Direction {
  Up,
  Down,
  Left,
  Right
}

here Direction.Up has the value of 0, Direction.Down a value of 1

literal enum

type validStrings = "hello" | "world" | "it's me"

any type

let myListOfThings: any[] = [1,2, "Three", { four: 4} ]
myListOfThings.forEach( i => console.log(i))

nullable

let myvar:number | null = null  // OK
let var2:string = null //invalid
let var3:string | null = null // OK

union

type stringFn = () => string // alias for the type

function print(x: string | stringFn) {
  if(typeof x == "string") return console.log(x)
  console.log(x())
}

Interfaces

In a similar way to types, interfaces allow us to define what I like to call “types for objects.”

interface IMyProps {
  name: string,
  age: number,
  city: string
}

function sayHello( myProps: IMyProps) {
  console.log(`Hello there ${myProps.name}`)
}

optional properties

interface IMyProps {
  name: string
  age: number
  city?: string
  findCityCoordinates?(): number
}

mixing with optional chainning:

function sayHello( myProps: IMyProps) {
  console.log(`Hello there ${myProps.name}, you're ${myProps.age} years old and live in ${myProps.city?.toUpperCase()}`)
}

Read-only properties

interface IPerson {
  readonly name: string,
  age: number
}

Interfaces for functions

interface Greeter {
  (name: string, age: number, city: string): void
}

const greeterFn: Greeter = function(n: string, a: number, city: string) {
  console.log(`Hello there ${n}, you're ${a} years old and live in ${city.toUpperCase()}`)
}

function asyncOp(callback: Greeter) {
  ///do async stuff here...
  callback("Fernando", 37, "Madrid")
}

classes

class Person {
  f_name: string
  l_name: string

  constructor(fn: string, ln: string) {
    this.f_name = fn
    this.l_name = ln
  }

  fullName(): string {
    return this.f_name + " " + this.l_name
  }
}

Private modifier

TypeScript implemented two versions, one following the classic standards using the private keyword and one following the way it’ll be implemented in the next version of ECMAScript, using the # character.

class Square {
  side: number
  private area: number
  #perimeter: number

  constructor(s: number) {
    this.side = s
    this.area = this.side * this.side
    this.#perimeter = this.side * 4
  }
}

Protected modifier

class Geometry {
  protected area: number
  protected perimeter: number
  constructor() {
    this.area = 0
    this.perimeter = 0
  }
}

accessors

class Geometry {
   protected area: number
   protected perimeter: number
   constructor() {
       this.area = 0
       this.perimeter = 0
   }
}
class Square extends Geometry{

  private side: number

  constructor(s: number) {
    super()
    this.side = s
    this.area = this.side * this.side
    this.perimeter = this.side * 4
  }

  set Side(value: number) {
    this.side = value
    this.area = this.side * this.side
  }

  get Side() {
    return this.side
  }

  get Area() {
    return this.area
  }
}

Static and abstract classes

type Point = {
  x: number,
  y: number
}

class Grid {

  static origin: Point = {x: 0, y: 0};

  calculateDistanceFromOrigin(point: Point) {
    let xDist = (point.x - Grid.origin.x);
    let yDist = (point.y - Grid.origin.y);
    return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale;
  }

  constructor (public scale: number) { }
}

abstract class Geometry {

  protected area: number

  protected perimeter: number

  constructor() {
    this.area = 0
    this.perimeter = 0
  }
}

mixins

(I don't really like mixins, read later)

3. Living a Secure Life

“Everything’s allowed” flag

$ deno run --allow-all your-script.ts

to enable access to this particular section of our system, we’ll need the --allow-env flag.

$ deno run --allow-env script.ts

Allowing access to the network interface

$ deno run --allow-net=github.com,gitlab.com myscript.ts

Allowing plugins to be used

--allow-plugin

Allowing reading from the disk and writing to it

$ deno run --allow-read=/etc/ yourscript.ts
$ deno run --allow-write=/your-app-folder/logs --allow-read=/your-app-folder/config/default.ini,/your-app-folder/config/credentials.ini yourscript.ts

Allowing your script to spawn new subprocesses

$ deno run --unstable --allow-run reader.ts

Checking for available permissions

const status = await Deno.permissions.query({ name: "read", path: "/etc" });
if (status.state === "granted") {
  data = await Deno.readFile("/etc/passwd");
}
const status = await Deno.permissions.request({ name: "env" });
if (status.state === "granted") {
  console.log(Deno.env.get("HOME"));
} else {
  console.log("'env' permission is denied.");
}
const status = await Deno.permissions.request({ name: "write", path: "/etc/passwd" });
//...
const readingStatus = await Deno.permissions.request({ name: "read", path: "./secret.txt" });
//...
const netStatus = await Deno.permissions.request({ name: "net", url: "http://github.com" });
//...
const envStatus= await Deno.permissions.revoke({ name: "env" });
if (envStatus.state === "granted") {
  console.log(Deno.env.get("HOME"));
} else {
  console.log("'env' permission is denied.");
}

denied even using the --allow-env flag

4. No More NPM

Dealing with external modules

Deno is dropping the require function and adopting the ES module standard for importing modules

import * as MyModule from './mymodule.ts'
import { get, has} from "https://deno.land/x/deno_lodash/mod.ts"
import { underline } from "https://deno.land/std@v0.39.0/fmt/colors.ts"

Handling packages

you can import everything in a single file; let’s call it deps.ts

//deps.ts
export * as MyModule from './mymodule.ts'
export {underline} from "https://deno.land/std@v0.39.0/fmt/colors.ts"

//script.ts
import {underline} from './deps.ts'
console.log(underline("This is underlined!"))

Locking your dependencies’ version

Deno provides --lock and --lock-write flags

// create the lockfile for the first time
$ deno run --lock=locks.json --lock-write script.ts

// when deploy project:
$ deno cache --reload --lock=locks.json deps.ts
$ deno run --lock=locks.json script.ts

Going experimental: Using import maps

(better check the latest version's documentation)

{
  "imports": {
    "fmt/": "https://deno.land/std@0.55.0/fmt/"
  }
}
import red from "fmt/colors.ts"
import printf from "fmt/printf.ts"
$ deno run --unstable --importmap=import_map.json myscript.ts

5. Existing Modules

sql

import { connect } from "https://deno.land/x/cotton/mod.ts";
const db = await connect({
  type: "sqlite", // available type: 'mysql', 'postgres', and 'sqlite'
  database: "db.sqlite",
  // other...
});

const users = await db.query("SELECT * FROM users;");
for (const user of users) {
  console.log(user.email);
}

mongodb

import { Database } from 'https://deno.land/x/denodb/mod.ts';
const db = new Database('mongo', {
  uri: 'mongodb://127.0.0.1:27017',
  database: 'test',
});

class Flight extends Model {
  static fields = {
    _id: {
      primaryKey: true,
    },
  };
}

const flight = new Flight();
flight.departure = 'Dublin';
flight.destination = 'Paris';
flight.flightDuration = 3;
await flight.save()

redis

import { connect } from "https://denopkg.com/keroxp/deno-redis/mod.ts";

const redis = await connect({
  hostname: "127.0.0.1",
  port: 6379
});

const ok = await redis.set("hoge", "fuga");
const fuga = await redis.get("hoge");

await redis.executor.exec("SET", "redis", "nice"); // => ["status", "OK"]
await redis.executor.exec("GET", "redis"); // => ["bulk", "nice"]

In order to make your code work with this module, you’ll need to provide network privileges using the --allow-net flag.


I think deno is very similar as golang, and even dart. lack of frontend support is a problem. It's clean and interesting, but I'll wait and see.