Typescript is a typed superset of JavaScript that compiles to plain JavaScript.
npm install -g typescript
tsc helloworld.ts
TypeScript is a typed language. This means that you can specify the type of a variable when you declare it, and only variables of that type can be assigned to that variable.
let a: number = 42;
// let variableName: type = value;
There are three main primitives in JavaScript and TypeScript.
boolean
- true or false valueslet isDone: boolean = false;
number
- whole numbers and floating point valueslet decimal: number = 6;
let hex: number = 0xf00d;
let binary: number = 0b1010;
let octal: number = 0o744;
string
- text values like "TypeScript Rocks"let color: string = "blue";
color = 'red';
There are also 2 less common primitives used in later versions of Javascript and TypeScript.
bigint
- whole numbers and floating point values, but allows larger negative and positive numbers than the number type.let big: bigint = 100n;
symbol
are used to create a globally unique identifier.Type inference is a way to predict the type of a variable based on its value.
let a = 42; // a is a number
When creating a variable, there are two main ways TypeScript assigns a type:
let firstName: string = "Dylan";
Implicit - TypeScript will guess the type:
let firstName = "Dylan";
Error in Type Assignment You can't re-declare a variable with a different type b/c its already delcare
let a: number = 42; // a is a number
a = "hello"; // error TS2322: Type '"hello"' is not assignable to type 'number'.
any
- TypeScript will not check the type of this variablelet a: any = 42;
a = "hello";
unknown
- similar to any, but you cannot access any properties of an unknown type, nor can you call/construct them.let a: unknown = 30;
let b = a === 123;
let c = a + 10;
never
- represents the type of values that never occur. For example, never is the return type for a function expression or an arrow function expression that always throws an exception or one that never returns.function error(message: string): never {
throw new Error(message);
}
void
- the absence of having any type at all. For example, declaring variables of type void is not useful because you can only assign undefined or null to them.function warnUser(): void {
console.log("This is my warning message");
}
null
- represents an intentional absence of an object value.let a: null = null;
undefined
- is a variable that has been declared, but no value has been assigned to it.let a: undefined = undefined;
object
- represents any non-primitive type.let a: object = {
b: "x"
};
never
- represents the type of values that never occur. For example, never is the return type for a function expression or an arrow function expression that always throws an exception or one that never returns.function error(message: string): never {
throw new Error(message);
}
Array
- represents a list of elements of a single type.let list: number[] = [1, 2, 3];
Tuple
- represents a list of elements of a single type, where the type of each element is known. You can think of a tuple as an array with a fixed number of elements.let x: [string, number];
x = ["hello", 10]; // OK
x = [10, "hello"]; // Error
Literal Types
- allow you to specify the exact value a string, number, or boolean must have.let a: "hello" = "hello";
a = "howdy"; // Error!
Non-Null Assertion Operator
- is an exclamation point (!) that tells TypeScript to temporarily suspend strict null checks.function liveDangerously(x?: number | null) {
// No error
console.log(x!.toFixed());
}
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 subtyping”. In TypeScript, interfaces fill the role of naming these types, and are a powerful way of defining contracts within your code as well as contracts with code outside of your project.
interface Person {
firstName: string;
lastName: string;
}
function greeter(person: Person) {
return "Hello, " + person.firstName + " " + person.lastName;
}
let user = { firstName: "Jane", lastName: "User" };
document.body.innerHTML = greeter(user);
Union
- allows us to use more than one type for a value.let a: number | boolean = 35;
a = true;
Intersection
- allows us to combine multiple types into one.interface Order {
id: string;
amount: number;
currency: string;
}
interface Stripe {
card: string;
cvc: string;
}
type CheckoutCard = Order & Stripe;
let order: CheckoutCard = {
id: "xj28s",
amount: 100,
currency: "USD",
card: "1000 2000 3000 4000",
cvc: "123"
};
Function
- is a special type that represents a JavaScript function.: number
here specifies that this function returns a number// the `: number` here specifies that this function returns a number
function getTime(): number {
return new Date().getTime();
}
: void
here specifies that this function doesn't return anything// the `: void` here specifies that this function doesn't return anything
function printHello(): void {
console.log('Hello!');
}
: never
here specifies that this function never returns anything// the `: never` here specifies that this function never returns anything
function throwError(errorMsg: string): never {
throw new Error(errorMsg);
}
: unknown
here specifies that this function returns an unknown type// the `: unknown` here specifies that this function returns an unknown type
function getID(id: number): unknown {
return id;
}
: any
here specifies that this function returns any type// the `: any` here specifies that this function returns any type
function getID(id: number): any {
return id;
}
parameter: type
here specifies that this function takes in a parameter of a certain type// the ` parameter: type` here specifies that this function takes in a parameter of a certain type
function addNumbers(a: number, b: number): number {
return a + b;
}
parameter?: type
here specifies that this function takes in an optional parameter of a certain type// the ` parameter?: type` here specifies that this function takes in an optional parameter of a certain type
function addNumbers(a: number, b?: number): number {
return a + b;
}
parameter: type = value
here specifies that this function takes in a parameter of a certain type with a default value// the ` parameter: type = value` here specifies that this function takes in a parameter of a certain type with a default value
function addNumbers(a: number, b: number = 10): number {
return a + b;
}
parameter: type[]
here specifies that this function takes in a parameter of a certain type as an array// the ` parameter: type[]` here specifies that this function takes in a parameter of a certain type as an array
function addNumbers(a: number, b: number[]): number {
return a + b[0];
}
parameter: ...type[]
here specifies that this function takes in a parameter of a certain type as an array// the ` parameter: ...type[]` here specifies that this function takes in a parameter of a certain type as an array
function addNumbers(a: number, ...b: number[]): number {
return a + b[0];
}
parameter: (parameter: type) => type
here specifies that this function takes in a parameter of a certain type as an array// the ` parameter: (parameter: type) => type` here specifies that this function takes in a parameter of a certain type as an array
function addNumbers(a: number, b: (c: number) => number): number {
return a + b(10);
}
Optional
- parameters are parameters that don’t have to be included when the function is called.function printIngredient(quantity: string, ingredient: string, extra?: string) {
console.log(`${quantity} ${ingredient} ${extra ? ` ${extra}` : ""}`);
}
printIngredient("1C", "Flour");
printIngredient("1C", "Sugar", "something else");
Default
- parameters are parameters that take a default value if no argument is passed to the function for that parameter.function printIngredient(quantity: string, ingredient: string, extra: string = "") {
console.log(`${quantity} ${ingredient} ${extra}`);
}
printIngredient("1C", "Flour");
printIngredient("1C", "Sugar", "something else");
Rest
- parameters are similar to optional parameters, but they are declared with a prefix of three periods (...). This tells the compiler to create an array of parameters of that type from all the remaining parameters in the function.function addNumbers(...nums: number[]) {
return nums.reduce((total, num) => total + num, 0);
}
addNumbers(1, 2, 3, 4, 5); // returns 15
function pow(x: number, y: number): number {
return Math.pow(x, y);
}
pow(5, 10); // returns 9765625
Function Signature
- is a way to define a function where we only define the function type, but not the implementation.let myFunc: (a: number, b: number) => number;
myFunc = (a: number, b: number) => {
return a + b;
};
Function Overloading
- is a way to define multiple function signatures for the same function name. This is how we can create functions that are more flexible.function makeDate(timestamp: number): Date;
function makeDate(m: number, d: number, y: number): Date;
function makeDate(mOrTimestamp: number, d?: number, y?: number): Date {
if (d !== undefined && y !== undefined) {
return new Date(y, mOrTimestamp, d);
} else {
return new Date(mOrTimestamp);
}
}
Type aliases create a new name for a type. Type aliases are sometimes similar to interfaces, but can name primitives, unions, tuples, and any other types that you’d otherwise have to write by hand.
type Name = string;
type NameResolver = () => string;
type NameOrResolver = Name | NameResolver;
function getName(n: NameOrResolver): Name {
if (typeof n === "string") {
return n;
} else {
return n();
}
}
Type Aliases
- allow us to create a new name for a type. Type aliases are sometimes similar to interfaces, but can name primitives, unions, tuples, and any other types that you’d otherwise have to write by hand.type Age = number;
type Person = {
name: string;
age: Age;
};
const age: Age = 55;
const driver: Person = {
name: "James May",
age: age
};
class Student {
fullName: string;
constructor(public firstName: string, public middleInitial: string, public lastName: string) {
this.fullName = firstName + " " + middleInitial + " " + lastName;
}
}
interface Person {
firstName: string;
lastName: string;
}
function greeter(person: Person) {
return "Hello, " + person.firstName + " " + person.lastName;
}
Generics is a way to create reusable components. Generics provide variables to types. A common example is an array. An array without generics could contain anything. An array with generics can describe the values that the array contains.
function identity<T>(arg: T): T {
return arg;
}
Enums allow us to define a set of named constants. Using enums can make it easier to document intent, or create a set of distinct cases. TypeScript provides both numeric and string-based enums.
enum Color {Red, Green, Blue}
let c: Color = Color.Green;
Type annotations in TypeScript are lightweight ways to record the intended contract of the function or variable. In this case, we intend the greeter function to be called with a single string parameter. We can try changing the call greeter to pass an array instead:
function greeter(person: string) {
return "Hello, " + person;
}
let user = [0, 1, 2];
document.body.innerHTML = greeter(user);
TypeScript knows the JavaScript language and will generate types for you. For example, if you write the number 42, TypeScript will understand that you want a number and will generate the type number for you.
let a = 42; // a is a number
you can't re-declare a variable with a different type b/c its already delcare
let a = 42; // a is a number
a = "hello"; // error TS2322: Type '"hello"' is not assignable to type 'number'.
To create an object with an inferred type which includes name: string
and id: number
, you can write:
let obj = {
name: "John",
id: 1
};
You can also explicitly declare the type of the object:
let obj: {
name: string;
id: number;
} = {
name: "John",
id: 1
};
Type assertions are a way to tell the compiler “trust me, I know what I’m doing.”
let a: any = "this is a string";
let b = (<string>a).toUpperCase();
Modules are executed within their own scope, not in the global scope; this means that variables, functions, classes, etc. declared in a module are not visible outside the module unless they are explicitly exported using one of the export forms. Conversely, to consume a variable, function, class, interface, etc. exported from a different module, it has to be imported using one of the import forms.
export interface StringValidator {
isAcceptable(s: string): boolean;
}
Namespaces are simply named JavaScript objects in the global namespace. This makes namespaces a very simple construct to use. They can span multiple files, and can be concatenated using --outFile. Namespaces can be a good way to structure your code in a Web Application, with all dependencies included as <script> tags in your HTML page.
namespace Validation {
export interface StringValidator {
isAcceptable(s: string): boolean;
}
}
TypeScript has a feature called declaration merging. This feature allows you to write multiple declarations and have them all appear as a single declaration.
interface Box {
height: number;
width: number;
}
interface Box {
scale: number;
}
let box: Box = {height: 5, width: 6, scale: 10};
Triple-slash directives are single-line comments containing a single XML tag. The contents of the comment are used as compiler directives.
/// <reference path="..." />
TypeScript is a structural type system. When we compare two different types, regardless of where they came from, if the types of all members are compatible, then we say the types themselves are compatible.
interface Point {
x: number;
y: number;
}
function logPoint(p: Point) {
console.log(`${p.x}, ${p.y}`);
}
const point = { x: 12, y: 26 };
logPoint(point);
A mixin is a class that contains methods for use by other classes without having to be the parent class of those other classes.
class Disposable {
isDisposed: boolean;
dispose() {
this.isDisposed = true;
}
}
class Activatable {
isActive: boolean;
activate() {
this.isActive = true;
}
deactivate() {
this.isActive = false;
}
}
class SmartObject implements Disposable, Activatable {
constructor() {
setInterval(() => console.log(this.isActive + " : " + this.isDisposed), 500);
}
interact() {
this.activate();
}
// Disposable
isDisposed: boolean = false;
dispose: () => void;
// Activatable
isActive: boolean = false;
activate: () => void;
deactivate: () => void;
}
applyMixins(SmartObject, [Disposable, Activatable]);
let smartObj = new SmartObject();
setTimeout(() => smartObj.interact(), 1000);
JSX is a syntax extension to JavaScript. It is similar to a template language, but it has full power of JavaScript. JSX gets compiled to React.createElement() calls which return plain JavaScript objects called “React elements”. You can also use JSX inside of TypeScript.
interface Props {
name: string;
X: number;
Y: number;
}
declare function AnotherComponent(props: Props): JSX.Element;
React is a JavaScript library for building user interfaces. It is the view layer for web applications.
import * as React from "react";
import * as ReactDOM from "react-dom";
interface HelloProps {
compiler: string;
framework: string;
}
class Hello extends React.Component<HelloProps, {}> {
render() {
return (
<h1>
Hello from {this.props.compiler} and {this.props.framework}!
</h1>
);
}
}
ReactDOM.render(
<Hello compiler="TypeScript" framework="React" />,
document.getElementById("example")
);
Documentation Links