handbook
https://www.typescriptlang.org/docs/handbook/typescript-from-scratch.html
TypeScript for the New Programmer
Syntax
TypeScript is a language that is a superset of JavaScript: JS syntax is therefore legal TS.
Runtime Behavior
TypeScript is also a programming language that preserves the runtime behavior of JavaScript
TypeScript for JavaScript Programmers
Types by Inference
let helloWorld = "Hello World";
Defining Types
interface User {
name: string;
id: number;
}
const user: User = {
name: "Hayes",
id: 0,
};
Composing Types
type MyBool = true | false;
type WindowStates = "open" | "closed" | "minimized";
function getLength(obj: string | string[]) {
return obj.length;
}
string typeof s === "string"
number typeof n === "number"
boolean typeof b === "boolean"
undefined typeof undefined === "undefined"
function typeof f === "function"
array Array.isArray(a)
Generics
type StringArray = Array<string>;
type NumberArray = Array<number>;
type ObjectWithNameArray = Array<{ name: string }>;
interface Backpack<Type> {
add: (obj: Type) => void;
get: () => Type;
}
Structural Type System
One of TypeScript’s core principles is that type checking focuses on the shape that values have. This is sometimes called “duck typing” or “structural typing”.
The Basics
JavaScript only truly provides dynamic typing - running the code to see what happens.
tsc, the TypeScript compiler
npm install -g typescript
tsc hello.ts
Emitting with Errors
tsc --noEmitOnError hello.ts
Downleveling
By default TypeScript targets ES3, an extremely old version of ECMAScript. We could have chosen something a little bit more recent by using the target option
tsc --target es2015 hello.ts
Strictness
TypeScript has several type-checking strictness flags that can be turned on or off
"strict": true in a tsconfig.json toggles them all on simultaneously, but we can opt out of them individually. The two biggest ones you should know about are noImplicitAny and strictNullChecks.
- noImplicitAny: TypeScript doesn’t try to infer types for us and instead falls back to the most lenient type: any
- strictNullChecks: By default, values like null and undefined are assignable to any other type
Everyday Types
The primitives: string, number, and boolean
JavaScript does not have a special runtime value for integers, so there’s no equivalent to int or float - everything is simply number
Arrays, any, Functions
Apart from primitives, the most common sort of type you’ll encounter is an object type.
Object types can also specify that some or all of their properties are optional. To do this, add a ? after the property name
Union Types
A union type is a type formed from two or more other types, representing values that may be any one of those types
Type Aliases
A type alias is a name for any type
Note that aliases are only aliases - you cannot use type aliases to create different/distinct “versions” of the same type. When you use the alias, it’s exactly as if you had written the aliased type.
type ID = number | string;
type UserInputSanitizedString = string;
Interfaces
Being concerned only with the structure and capabilities of types is why we call TypeScript a structurally typed type system.
Differences Between Type Aliases and Interfaces
the key distinction is that a type cannot be re-opened to add new properties vs an interface which is always extendable.
interface Window {
title: string
}
interface Window {
ts: TypeScriptAPI
}
Type Assertions
const myCanvas = document.getElementById("main_canvas") as HTMLCanvasElement;
Sometimes this rule can be too conservative and will disallow more complex coercions that might be valid. If this happens, you can use two assertions
const a = (expr as any) as T;
Literal Types
by combining literals into unions, you can express a much more useful concept - for example, functions that only accept a certain set of known values
function printText(s: string, alignment: "left" | "right" | "center") {
// ...
}
The type boolean itself is actually just an alias for the union true | false
You can change the inference by adding a type assertion in either location
// Change 1:
const req = { url: "https://example.com", method: "GET" as "GET" };
// Change 2
handleRequest(req.url, req.method as "GET");
You can use as const to convert the entire object to be type literals
const req = { url: "https://example.com", method: "GET" } as const;
handleRequest(req.url, req.method);
null and undefined
strictNullChecks off/on
function liveDangerously(x?: number | null) {
// No error
console.log(x!.toFixed());
}
enums
Unlike most TypeScript features, this is not a type-level addition to JavaScript but something added to the language and runtime
Narrowing
typeof type guards
Within our if check, TypeScript sees typeof padding === "number" and understands that as a special form of code called a type guard
It looks at these special checks (called type guards) and assignments, and the process of refining types to more specific types than declared is called narrowing
in JavaScript, typeof null is actually "object"
Truthiness narrowing
In JavaScript, constructs like if first “coerce” their conditions to booleans to make sense of them
You can always coerce values to booleans by running them through the Boolean function, or by using the shorter double-Boolean negation
Equality narrowing
checking whether something == null actually not only checks whether it is specifically the value null - it also checks whether it’s potentially undefined
function example(x: string | number, y: string | boolean) {
if (x === y) {