TypeScript

The base type

boolean

let isDone: boolean = false;
Copy the code

number

let decLiteral: number = 6;
let hexLiteral: number = 0xf00d;
let binaryLiteral: number = 0b1010;
let octalLiteral: number = 0o744;
Copy the code

string

let name: string = "bob";
name = "smith";
Copy the code

array

First, the element type can be followed by [] to represent an array of elements of that type:

let list: number[] = [1.2.3];
Copy the code

The second way is to use Array generics, Array< element type > :

let list: Array<number> = [1.2.3];
Copy the code

tuple

The tuple type allows you to represent an array with a known number and type of elements that need not be of the same type

// Declare a tuple type
let x: [string.number];
// Initialize it
x = ['hello'.10]; // OK
// Initialize it incorrectly
x = [10.'hello']; // Error
Copy the code

enum

enum Color {Red, Green, Blue}
let c: Color = Color.Green;
Copy the code

By default, elements are numbered from 0. You can also manually specify the values of the members. For example, let’s change the above example to number from 1:

enum Color {Red = 1, Green, Blue}
let c: Color = Color.Green;
Copy the code

Alternatively, all manual assignments are used:

enum Color {Red = 1, Green = 2, Blue = 4}
let c: Color = Color.Green;
Copy the code

One of the conveniences provided by an enumerated type is that you can refer to its name by enumeration. For example, if we know that the value is 2, but are not sure which name in Color it maps to, we can look for the corresponding name:

enum Color {Red = 1, Green, Blue}
let colorName: string = Color[2];

console.log(colorName);  // Display 'Green' because its value is 2 in the code above
Copy the code

any

Sometimes we want to specify a type for variables whose type is not known at programming time. These values may come from dynamic content, such as user input or third-party code libraries. In this case, we don’t want the type checker to check these values and just pass them through compile-time checks. We can then mark these variables with type any:

let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // okay, definitely a boolean
Copy the code

void

In a way, void is like the opposite of any; it means there is no type at all. When a function returns no value, you usually see the return type void:

function warnUser() :void {
    console.log("This is my warning message");
}
Copy the code

Declaring a void variable doesn’t do much good, because you can only assign undefined and null to it:

let unusable: void = undefined;
Copy the code

Null, and undefined

In TypeScript, undefined and null have their own types called undefined and NULL, respectively. Like void, their own types are not very useful:

// Not much else we can assign to these variables!
let u: undefined = undefined;
let n: null = null;
Copy the code

By default null and undefined are subtypes of all types. This means that you can assign null and undefined to variables of type number.

However, when you specify strictNullChecks, null and undefined can only be assigned to void and their respective checks. This avoids many common problems. Maybe somewhere you want to pass in a string or null or undefined, you can use the combined type string | null | is undefined. Again, we’ll cover union types later.

Note: We encourage the use of strictNullChecks wherever possible, but in this manual we assume that this flag is closed.

never

The never type represents the types of values that never exist. For example, the never type is the return type of function expressions or arrow function expressions that always throw an exception or have no return value at all; Variables can also be of type never, when they are bound by type protection that is never true.

The never type is a subtype of any type and can be assigned to any type; However, no type is a subtype of never or can be assigned to a type of never (except never itself). Even any cannot be assigned to never.

Here are some functions that return type never:

// A function that returns never must have an unreachable end
function error(message: string) :never {
    throw new Error(message);
}

// The inferred return value type is never
function fail() {
    return error("Something failed");
}

// A function that returns never must have an unreachable end
function infiniteLoop() :never {
    while (true) {}}Copy the code

object

Object represents a non-primitive type, that is, a type other than number, string, Boolean, symbol, NULL, or undefined.

Use the object type to better represent apis like Object.create. Such as:

declare function create(o: object | null) :void;

create({ prop: 0 }); // OK
create(null); // OK

create(42); // Error
create("string"); // Error
create(false); // Error
create(undefined); // Error
Copy the code

Types of assertions

Sometimes you’ll find that you know more about a value than TypeScript does. Usually this happens when you clearly know that an entity has a more exact type than its existing type.

Type assertions are a way of telling the compiler, “Trust me, I know what I’m doing.” Type assertion is like conversion in other languages, but without special data checking and deconstruction. It has no run-time impact, only at compile time. TypeScript assumes that you, the programmer, have done the necessary checks.

Type assertions come in two forms. The first is the Angle bracket syntax:

let someValue: any = "this is a string";

let strLength: number = (<string>someValue).length;
Copy the code

The other is the as syntax:

let someValue: any = "this is a string";

let strLength: number = (someValue as string).length;
Copy the code

The two forms are equivalent. Which to use is mostly a matter of personal preference; However, when you use JSX in TypeScript, only AS syntax assertions are allowed.

Interface interface

interface LabelledValue {
  label: string;
}

function printLabel(labelledObj: LabelledValue) {
  console.log(labelledObj.label);
}

let myObj = {size: 10.label: "Size 10 Object"};
printLabel(myObj);
Copy the code

Optional attribute

Not all attributes in the interface are required. Some exist only under certain conditions, or not at all. Optional properties are commonly used in the “Option Bags” mode, where only part of the parameter object passed to the function is assigned a value.

interfaceSquareConfig { color? :string; width? :number;
}
Copy the code

Read-only property

Some object properties can only change their value when the object is created. You can specify read-only properties with readonly before the property name:

interface Point {
    readonly x: number;
    readonly y: number;
}
Copy the code

TypeScript has the ReadonlyArray

type, which is similar to Array

except that all mutable methods are removed, thus ensuring that arrays can never be modified after they are created:

let a: number[] = [1.2.3.4];
let ro: ReadonlyArray<number> = a;
ro[0] = 12; // error!
ro.push(5); // error!
ro.length = 100; // error!
a = ro; // error!
Copy the code

Function types

interface SearchFunc {
  (source: string.subString: string) :boolean;
}

let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
  let result = source.search(subString);
  return result > -1;
}
Copy the code

Indexable type

interface StringArray {
  [index: number] :string;
}

let myArray: StringArray;
myArray = ["Bob"."Fred"];

let myStr: string = myArray[0];
Copy the code
class Animal {
    name: string;
}
class Dog extends Animal {
    breed: string;
}
Copy the code
interface NumberDictionary {
  [index: string] :number;
  length: number;    // Yes, length is number
  name: string       // Error, the type of 'name' does not match the type of the index type returned value
}
Copy the code

Class types

interface ClockInterface {
    currentTime: Date;
}

class Clock implements ClockInterface {
    currentTime: Date;
    constructor(h: number, m: number){}}Copy the code

Inherited interface

interface Shape {
    color: string;
}

interface Square extends Shape {
    sideLength: number;
}

let square = <Square>{};
square.color = "blue";
square.sideLength = 10;
Copy the code

An interface can inherit multiple interfaces to create a composite interface of multiple interfaces.

interface Shape {
    color: string;
}

interface PenStroke {
    penWidth: number;
}

interface Square extends Shape, PenStroke {
    sideLength: number;
}

let square = <Square>{};
square.color = "blue";
square.sideLength = 10;
square.penWidth = 5.0;
Copy the code

Mixed type

interface Counter {
    (start: number) :string;
    interval: number;
    reset(): void;
}

function getCounter() :Counter {
    let counter = <Counter>function (start: number) {}; counter.interval =123;
    counter.reset = function () {};return counter;
}

let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;
Copy the code

Interface inheritance class

class Control {
    private state: any;
}

interface SelectableControl extends Control {
    select(): void;
}

class Button extends Control implements SelectableControl {
    select(){}}class TextBox extends Control {
    select(){}}// Error: The "Image" type is missing the "state" attribute.
class Image implements SelectableControl {
    select(){}}class Location {}Copy the code

In the example above, the SelectableControl contains all members of Control, including the private member state. Since state is a private member, only subclasses of Control can implement the SelectableControl interface. Because only subclasses of Control can have a private member state declared on Control, compatibility with private members is required.

Within the Control class, private member States are allowed to be accessed through instances of the SelectableControl. In fact, the SelectableControl interface is the same as the Control class with the Select method. The Button and TextBox classes are subclasses of the SelectableControl (because they both inherit from Control and have select methods), but the Image and Location classes are not

class

public

All class members are decorated with public by default

private

When a member is marked private, it cannot be accessed outside the class in which it is declared. Such as:

class Animal {
    private name: string;
    constructor(theName: string) { this.name = theName; }}new Animal("Cat").name; // Error: 'name' is private.
Copy the code

protected

Protected modifiers behave much like private modifiers, with one difference: protected members are still accessible in derived classes.

class Person {
    protected name: string;
    constructor(name: string) { this.name = name; }}class Employee extends Person {
    private department: string;

    constructor(name: string, department: string) {
        super(name)
        this.department = department;
    }

    public getElevatorPitch() {
        return `Hello, my name is The ${this.name} and I work in The ${this.department}. `; }}let howard = new Employee("Howard"."Sales");
console.log(howard.getElevatorPitch());
console.log(howard.name); / / error
Copy the code

readonly

Read-only attributes must be initialized at declaration time or in a constructor

get | set

et passcode = "secret passcode";

class Employee {
    private _fullName: string;

    get fullName() :string {
        return this._fullName;
    }

    set fullName(newName: string) {
        if (passcode && passcode == "secret passcode") {
            this._fullName = newName;
        }
        else {
            console.log("Error: Unauthorized update of employee!"); }}}let employee = new Employee();
employee.fullName = "Bob Smith";
if (employee.fullName) {
    alert(employee.fullName);
}
Copy the code

Accessors require that you set the compiler to output ECMAScript 5 or higher. Downgrading to ECMAScript 3 is not supported. Second, accessors with only GET and no set are automatically inferred as readonly. This is helpful when generating.d.ts files from code, because users who exploit this property will see that it is not allowed to change its value.

static

class Grid {
    static origin = {x: 0.y: 0};
    calculateDistanceFromOrigin(point: {x: number; y: number; }) {
        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) {}}let grid1 = new Grid(1.0);  // 1x scale
let grid2 = new Grid(5.0);  // 5x scale

console.log(grid1.calculateDistanceFromOrigin({x: 10.y: 10}));
console.log(grid2.calculateDistanceFromOrigin({x: 10.y: 10}));
Copy the code

abstract

Abstract classes are used as base classes for other derived classes. They are generally not instantiated directly. Unlike interfaces, abstract classes can contain implementation details of members. The abstract keyword is used to define abstract classes and abstract methods within abstract classes.

abstract class Department {
    
    constructor(public name: string) {}
    
    printName(): void {
        console.log('Department name: ' + this.name);
    }

    abstract printMeeting(): void; // Must be implemented in a derived class
}

class AccountingDepartment extends Department {

    constructor() {
        super('Accounting and Auditing'); // Super () must be called in the constructor of a derived class
    }

    printMeeting(): void {
        console.log('The Accounting Department meets each Monday at 10am.');
    }

    generateReports(): void {
        console.log('Generating accounting reports... '); }}let department: Department; // Allows you to create a reference to an abstract type
department = new Department(); // Error: cannot create an instance of an abstract class
department = new AccountingDepartment(); // Allows instantiation and assignment of an abstract subclass
department.printName();
department.printMeeting();
department.generateReports(); // Error: method does not exist in declared abstract class
Copy the code

Use classes as interfaces

As we saw in the previous section, a class definition creates two things: the instance type of the class and a constructor. Because classes create types, you can use classes where interfaces are allowed.

class Point {
    x: number;
    y: number;
}

interface Point3d extends Point {
    z: number;
}

let point3d: Point3d = {x: 1.y: 2.z: 3};
Copy the code

function

Function types

function add(x: number, y: number) :number {
    return x + y;
}

let myAdd = function(x: number, y: number) :number { return x + y; };
Copy the code

The function type consists of two parts: the parameter type and the return value type. Both are needed when writing full function types. We write out the parameter types as parameter lists, specifying a name and type for each parameter. The name is just for readability. We could also write:

let myAdd: (baseValue: number, increment: number) = > number = function(x: number, y: number) :number { return x + y; };
Copy the code

The generic

Generic variables

Using any causes the function to accept arG arguments of any type, and some information is lost: the type passed in should be the same as the type returned. If we pass in a number, we just know that any type of value can be returned.

Therefore, we need a way to make the type of the return value the same as the type of the parameter passed in. Here, we use a type variable, which is a special variable that only represents a type, not a value.

function identity<T> (arg: T) :T {
    return arg;
}
Copy the code

The generic type

Some types of attributes do not necessarily exist, and exceptions occur if you do not specify a generic type

// Abnormal condition
function loggingIdentity<T> (arg: T[]) :T[] {
    console.log(arg.length);  // Array has a .length, so no more error
    return arg;
}

// Normal condition
function loggingIdentity<T> (arg: Array<T>) :Array<T> {
    console.log(arg.length);  // Array has a .length, so no more error
    return arg;
}
Copy the code

A generic class

Generic classes look much like generic interfaces. Generic classes use (<>) to enclose generic types after the class name.

class GenericNumber<T> {
    zeroValue: T;
    add: (x: T, y: T) = > T;
}

let myGenericNumber = new GenericNumber<number> (); myGenericNumber.zeroValue =0;
myGenericNumber.add = function(x, y) { return x + y; };
Copy the code

The enumeration

Using enumerations we can define constants with names. Use enumerations to clearly express intent or to create a differentiated set of use cases. TypeScript supports numeric and string-based enumerations.

Digital enumeration

enum Direction {
    Up = 1,
    Down,
    Left,
    Right
}
Copy the code

If a numeric enumeration is defined, the Up use is initialized to 1. The rest of the members will automatically grow from 1.

If Up does not define any data, it grows from 0

String enumeration

enum Direction {
    Up = "UP",
    Down = "DOWN",
    Left = "LEFT",
    Right = "RIGHT",}Copy the code

Because string enumerations have no self-growing behavior, string enumerations can be serialized well. In other words, if you are debugging and have to read a number of enumeration values at runtime, this value is usually difficult to read – it doesn’t useful information (though reverse mapping will help), string enumeration allows you to provide the meaning of a runtime and readable values, independent of the members of the enumeration name.

Heterogeneous enumeration (Heterogeneous enums)

Technically, enumerations can mix strings and numeric members, but it doesn’t seem like you’d do that:

enum BooleanLikeHeterogeneousEnum {
    No = 0,
    Yes = "YES",}Copy the code

Unless you really want to take advantage of JavaScript runtime behavior, we don’t recommend doing so.

Computed and constant members

Each enumerator takes a value, which can be constant or computed. Enumerators are treated as constants if:

  • It is the first member of the enumeration and has no initializer, in which case it is given the value 0:

    // E.X is constant:
    enum E { X }
    Copy the code
  • It has no initializer and the enumerator before it is a numeric constant. In this case, the value of the current enumerator is incremented by the value of its previous enumerator.

    // All enum members in 'E1' and 'E2' are constant.
    
    enum E1 { X, Y, Z }
    
    enum E2 {
        A = 1, B, C
    }
    Copy the code
  • Enumerator members are initialized with constant enumeration expressions. Constant enumerated expressions are a subset of TypeScript expressions that can be evaluated at compile time. An expression is a constant enumerated expression when it satisfies one of the following conditions:

    • An enumerated expression literal (mainly a string literal or a number literal)
    • A reference to a previously defined constant enumerator (which can be defined in a different enumeration type)
    • A bracketed constant enumeration expression
    • Unary operator+.-.~One of them applies to constant enumeration expressions
    • Constant enumeration expressions as binary operators+.-.*./.%.<<.>>.>>>.&.|.^Operation object of. If the constant enumeration expression is evaluatedNaNorInfinity, an error is reported at compile time.

Enumerators in all other cases are treated as values that need to be computed.

The type of the associative enumeration with the enumerator

There is a special subset of noncomputed constant enumerators: literal enumerators. A literal enumerator is a constant enumerator that has no initial value, or whose value is initialized to

  • Any string literal (e.g."foo"."bar"."baz")
  • Any numeric literal (e.g.1.100)
  • Apply unary-The numeric literal of a symbol (e.g.- 1.- 100.)

When all enumerators have literal enumeration values, it takes on a special semantics.

enum ShapeKind {
    Circle,
    Square,
}

interface Circle {
    kind: ShapeKind.Circle;
    radius: number;
}

interface Square {
    kind: ShapeKind.Square;
    sideLength: number;
}

let c: Circle = {
    kind: ShapeKind.Square,
    // ~~~~~~~~~~~~~~~~ Error!
    radius: 100,}Copy the code

Enumeration at runtime

Enumerations are objects that actually exist at run time. For example, the following enumeration:

enum E {
    X, Y, Z
}

function f(obj: { X: number }) {
    return obj.X;
}

// Works, since 'E' has a property named 'X' which is a number.
f(E);
Copy the code

Reverse mapping

enum Enum {
    A
}
let a = Enum.A;
let nameOfA = Enum[a]; // "A"
Copy the code

constThe enumeration

const enum Enum {
    A = 1,
    B = A * 2
}
Copy the code

External enumeration

declare enum Enum {
    A = 1,
    B,
    C = 2
}
Copy the code