JavaScript in 10 Days: Day 2
Today’s plan is to get through the TypeScript handbook and to skim as much of Crockford as possible, as there seem to be many things in the Crockford that are no longer applicable.
More emacs Setup
For getting started with editing pure JavaScript files, I followed this page and looked at one or two others.
js2-mode
js2-refactor
xref-js2
andag
The emacs setup is always a bit tricky, since I don’t have a very good knowledge of elisp and things like use-package
syntax. This version seems to work as a starting point.
Day 2 Talks / Articles
Articles referenced by Atencio on shadowing, private class fields, static fields
TypeScript Handbook
The Basics
- To compile a specifc file, run
tsc
with flags and filename. - To compile with
tsconfig.json
, runtsc
alone in directory with source code (where the tsconfig file denotes the root of a project) - the tsconfig handbook
Everyday Types
-
Optional object properties are specified by adding a
?
after the property name (instead of e.g. wrapping the type in aMaybe
) -
The optional flag can also be used by accessors:
console.log(obj.last?.toUpperCase());
-
Interfaces: similar to type aliases, but properties are extensible
-
Type assertions:
const myCanvas = document.getElementById("main_canvas") as HTMLCanvasElement;
orconst myCanvas = <HTMLCanvasElement>document.getElementById("main_canvas");
-
Literal types – string, number, and boolean; also can assert type
as const
-
Adding
!
after a variable asserts that its type is non-null -
Enums: TypeScript only (guide)
Narrowing
More on Functions
-
Call signatures for functions that have properties (!)
-
Constructor signatures are specified with a
new
keyword in front of a call signature -
Generics: need to specify a type parameter in
<>
:function firstElement<Type>(arr: Type[]): Type
-
Constraints – similar to ideas of type classes or extensible records
function longest<Type extends { length: number }>(a: Type, b: Type) {
-
Parameter defaults can be specified
-
Rest parameters with
...
syntax; same for rest arguments -
Parameter destructuring
Object Types
-
can combine destructring patterns for parameters with default values
-
readonly
keyword for properties (a bit likeconst
the referent can still change, but the reference cannot be written to) - index signatures
-
interfaces can be extended
extends
; they can be intersected&
(err… but his is actually a union of all the properties?) -
interfaces can take a type parameter…
-
ReadOnlyArray
, no constrctor:const roArray: ReadonlyArray<string> = ["red", "green", "blue"];
- tuples also support optional and rest parameters, readonly
Type Manipulation
-
Generic interfaces and classes, can build constraints with
extends
; class types can be used in generics (see mixins too) -
keyof
takes an object and returns union of its keys typeof
can be used on identifiers or their properties-
indexed access type to look up property of another type (when is this useful?)
-
conditional types – use ternary conditional expression in types
-
mapped types: generic type with union of PropertyKeys (often with
keyof
) - template literal types, instrinstic string manipulation types…
Classes
!
– definite assignment assertion used after class field name-
readonly – limits assignemnt to the constructor
- visibility:
public
,protected
,private
Modules
export{};
makes a file a module without imports or exports
JavaScript, the Good Parts
Chapter 6 Arrays -> Appendix B
Skimmed the chapters.
-
sorting is coerced to strings by default; provide comparison function to sort eg numbers
function (a, b) { return a - b }
-
the appendices A & B are maybe the most interesting parts of the book!
JoJ
None.
JoJ Code
None.
Other Code
I looked at the Eloquent JavaScript higher-order functions part and decided to write some standard cons list and map / folds.
Here is a cons list in the usual formulation, with constructors, using generic type parameters:
type ConsList<T> =
null |
[T, ConsList<T>]
function cons<T>(head: T, tail: ConsList<T>): ConsList<T> {
return [head, tail];
}
function fromArray<T>(arr: Array<T>): ConsList<T> {
let xs: ConsList<T> = null;
for (let i = arr.length - 1; i >= 0; i--) {
xs = cons(arr[i], xs)
}
return xs;
}
Here is foldr
with the same implementation as Haskell:
function foldR<T, U>(
f: ((x: T, acc: U) => U),
acc: U,
xs: ConsList<T>): U {
if (xs === null) {
return acc;
}
else {
let [h, t] = xs
return f(h, foldR(f, acc, t));
}
}
Now for example map
can be written with foldR
:
function mapFoldR<T, U>(f: (x: T) => U, xs: ConsList<T>): ConsList<U> {
let empty = null as ConsList<U>;
return foldR((a, b) => cons(f(a), b), empty, xs);
}
I then got stuck for a very long time trying to figure out a type error:
const xs = fromArray([1, 2, 3]);
console.log(map(x => x + 1, xs));
let empty: ConsList[<number> = null;
console.log(foldR((a, b) => cons(a, b), empty, xs)); // ERROR
console.log(mapFoldR(x => x + 1, xs));
It took getting a Stack Overflow answer to figure out the error.
let empty: ConsList[<number> = null; // Problem...
let empty = null as ConsList<number>; // OK
In short, the former causes TypeScript to narrow the type too much (to null
as opposed to ConsList<number>
. Good to know!
Correcting the type assertion, TypeScript is happy and the output is also as expected:
% node fold.js
[ 2, [ 3, [ 4, null ] ] ] // map (+1)
[ 1, [ 2, [ 3, null ] ] ] // foldr with cons
[ 2, [ 3, [ 4, null ] ] ] // map (+1) with foldR
Wrapping Up
Is TypeScript what happens when static-typing / functional programming concepts are applied to an inherently impure, dynamic language? It’s messy and there are many more ways (too many?) to do things, but it’s also more approachable (there is hardly any theory in the TypeScript handbook, unlike in any Haskell introduction).
With such tooling, it seems like consistent conventions and domain-specific best practices play should play a greater rol in producing scalable, reusable, correct code.
It’s very different from, say, the opinionated minimalism of Elm (oh, you want tuples longer than three? nah… you shouldn’t really use them).
As for Crockford’s book, I’m not sure I’d recommend it to someone in my position, as there are undoubtedly more modern alterantive out there. The appendices on awful and bad parts of the language are interesting, though.
Todo / To Read
TypeScript Handbook- Compiling with both TypeScript with Babel
- More chapters of
Crockfordand Atencio - Eloquent JavaScript has exercises at the end of chapters, which might be worth exploring
- Kyle Simpson, You Don’t Know JS
Atencio: ShadowingAtencio: “…proposals related to private class fields (http://mng.bz/YqVB) and static fields (http://mng.bz/5jgB)…”- Figure out how to use
outDir
(?) to compile.js
files to separate subdirectory