(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.