TypeScript -- basics

TypeScript -- basics

Write in front: This article is a little long, which is suitable for Xiaobai who is going to learn TS. if there is a certain basic God, you can ignore this article. The article is not completely original. Most of the content is moved from other articles on the Internet, and then add some of your own understanding and summary. If infringement is involved, please contact me and make rectification in time.

1, Basic type

1.1 String type

let name: string = "Zhang San";
// ES5: var name = "Zhang San";

1.2 Number type

let num: number = 3;
// ES5: var num = 3;

1.3 Boolean type

let bool: boolean = false;
// ES5: var bool = false;

1.4 Symbol type

const symb = Symbol();
let obj = {
  [symb]: "Zhang San"
}

console.log(obj[symb]); // Zhang San

1.5 Array type

let list: number[] = [1, 2, 3];
// ES5: var list = [1,2,3];

let list: Array<number> = [1, 2, 3]; // Array < number > belongs to generic syntax
// ES5: var list = [1,2,3];

1.6 Enum type
Enumeration type. Using enumeration, you can define some constants with names. Enumeration can be used to express the intention clearly or create a set of different use cases. TypeScript supports numeric and string enumeration.

  • i. Numeric enumeration
enum Direction {
  UP,
  RIGHT,
  DOWN,
  LEFT
}
let dir: Direction = Direction.UP;

// ES5:
"use strict";
var Direction;
(function(Direction) {
  Direction[(Direction["UP"] = 0)] = "UP";
  Direction[(Direction["RIGHT"] = 1)] = "RIGHT";
  Direction[(Direction["DOWN"] = 2)] = "DOWN";
  Direction[(Direction["LEFT"] = 3)] = "LEFT";
})(Direction || (Direction = {}));
var dir = Direction.UP;

By default, the initial value of UP is 0, and the remaining members will grow automatically from 1. In other words, direction The value of right is 1, direction The value of down is 2, direction The value of left is 3.

  • You can also set an initial value for the enumeration value, and the enumeration value will increase automatically from 1, that is, 1, 2, 3 and 4.
enum Direction {
  UP = 1,
  RIGHT,
  DOWN,
  LEFT
}
let dir: Direction = Direction.UP;

// ES5:
"use strict";
var Direction;
(function(Direction) {
  Direction[(Direction["UP"] = 1)] = "UP";
  Direction[(Direction["RIGHT"] = 2)] = "RIGHT";
  Direction[(Direction["DOWN"] = 3)] = "DOWN";
  Direction[(Direction["LEFT"] = 4)] = "LEFT";
})(Direction || (Direction = {}));
var dir = Direction.UP;
  • Set the initial value in the middle enumeration value. Enum will not care about or calculate the generation of this value, but will increase from 0. When meeting the set initial value, it will increase from this initial value.
enum Direction {
  UP,
  RIGHT,
  DOWN = 3,
  LEFT
}
let dir: Direction = Direction.UP;

// ES5:
"use strict";
var Direction;
(function(Direction) {
  Direction[(Direction["UP"] = 0)] = "UP";
  Direction[(Direction["RIGHT"] = 1)] = "RIGHT";
  Direction[(Direction["DOWN"] = 3)] = "DOWN";
  Direction[(Direction["LEFT"] = 4)] = "LEFT";
})(Direction || (Direction = {}));
var dir = Direction.UP;
  • Assignment by function. When declaring the initial value of enumeration, the value returned by the function can be assigned. Note that once one of the enumeration values is assigned by function, the enumeration values of all remaining parameters cannot have initialized values, otherwise Error will be reported.
funciton getVal(): number {
  return 1;
}

enum Direction {
  Up = getVal(),
  Right = getVal(),
  Down, // ERROR, the initial enumeration value cannot be given here
  Left = getVal(),
}
  • ii. String Enum
    String enumeration has no self growth behavior. Each enumeration value must be assigned with a string literal.
enum Direction {
  Up = "UP",
  Right = "RIGHT",
  Down = "DOWN",
  Left = "LEFT"
}
  • If the enumeration value is not assigned a string literal value, the enumeration value will default to the numerical enumeration value for self growth behavior.
  • Once string enumeration is used, all values must have initial values, otherwise an error will be reported.
enum Direction {
  Up = "UP",
  Right = "RIGHT",
  Down = "DOWN",
  Left // ERROR, initial value is required
}
  • iii. heterogeneous enumeration
    Enum supports enum members that can be either number or string, but this is not recommended. Because in fact, there is no point in doing so, unless it is absolutely necessary not to recommend it. It is also recommended to declare enumeration values of the same type.
enum Check {
  No = 0,
  Yes = "YES"
}

// ES5
(function (Check) {
  Check[Check["No"] = 0] = "No";
  Check["Yes"] = "YES"
})(Check || (Check = {}))

1.7 Any type

In Typescript, Any type can be classified as Any type. This makes Any type the top-level type of the type system (also known as global supertype).

let notType: any = 666;
notType = "Zhang San";
notType = false;

Typescript allows us to perform any operation on it without performing any form of check in advance:

let value: any;

value.foo.bar;
value.trim();
value();
new value();
value[0][1];

However, this is not in line with the original intention of Typescript design. In particular, it is unable to use a large number of protection mechanisms provided by the system, so it is generally rarely used.

1.8 Unknown type

Unknown is another top-level type of the system. All types of values can be assigned to unknown.

let value: unknown;
value = true;
value = 42;
value = "Hello World";
value = [];
value = {};
value = Math.random;
value = null;
value = undifined;
value = new TypeError();
value = Symbol();

However, the value of Unknown cannot be assigned to other types of variables, except Any and other variables of the same type.

let value: unknown;
let value1: unknown = value;
let value2: any = value;
let value3: boolean = value; // ERROR
let value4: number = value; // ERROR
let value5: string = value; // ERROR
let value6: object = value; // ERROR
let value7: any[] = value; // ERROR
let value8: Function = value; // ERROR

In addition, values of type Unknown cannot be used for other operations.

let value: unknown;

value.foo.bar; // ERROR
value.trim(); // ERROR
value(); // ERROR
new value(); // ERROR
value[0][1]; // ERROR

After setting the variable type of value to Unknown, these operations are no longer considered to be of the correct type. By changing Any type to Unknown type, we can change the configuration that is allowed to be changed to prohibit Any change.

1.8 Tuple type

Tuple type. TypeScript arrays are generally composed of values of the same type. If we want to store different types of values in a single variable, we can use tuples.

let tupleType: [string, boolean];
tupleType = ["Zhang San", true];

When using tuples, each attribute has an associated type, and the value of each attribute must be provided. If there is a type mismatch or no value, an error will be reported. We can access elements in tuples by subscript:

let tupleType: [string, boolean];
tupleType = ["Zhang San"]; // ERROR, the second value cannot be empty
tupleType = ["123"]; // ERROR, type mismatch

console.log(tupleType[0]); // Zhang San
console.log(tupleType[1]); // true

1.9 Void type

Void type is the opposite of Any type, indicating that there is no type. When a function has no return value, you can set the function type to this type:

function warnUser(): void {
  console.log("warning!");
}

// ES5
"use strict";
function warnUser() {
  console.log("warning!");
}

Note that declaring a variable of void type has no effect. In strict mode, the value of the variable can only be undefined:

let unusable: void = undefined;

1.9 Null and Undifined types

Null type:

let n: null = null;

Undifined type:

let u: undefined = undefined;

Note that the two are not interlinked and are consistent with JavaScript.

1.10 object, Object, {} type

  • i. object type
    The object type represents any type of non primitive (basic type) value, including objects, functions, arrays, and so on
let a: object;
a = {}; // OK
a = [1, 2, 3]; // OK
a = [1, true, "Zhang San"]; // OK
a = () => 1; // OK
a = 66; // ERROR, type number cannot be assigned to type object
  • For JavaScript, there are only (large) objects and no (small) objects. The (small) object is just a string returned by typeof judging the type.
  • For example, in ES6, the WeakMap requires that the key must be an object. The WeakMap defined in TypeScript uses the type of object constraint key:
interface WeakMap<K extends object, V> {
  delete(key: K): boolean;
  get(key: K): V | undefined;
  has(key: K): boolean;
  set(key: K, value: V): this;
}
  • ii. Object type
    TypeScript divides JavaScript Object into two interfaces to define:
  1. Object interface is used to define the prototype interface of object.js prototype:
interface Object {
  constructor: Function;
  toString(): string;
  toLocaleString(): string;
  valueOf(): Object;
  hasOwnProperty(v: PropertyKey): boolean;
  isPrototypeOf(v: Object): boolean;
  propertyIsEnumerable(v: PropertyKey): boolean;
}
  1. interface ObjectConstructor interface type is used to define the properties of an Object, such as Object create():
interface ObjectConstructor {
  new(value?: any): Object;
  (): any;
  (value: any): any;
  readonly prototype: Object;
  getPrototypeOf(o: any): any;
  getOwnPropertyNames(o: any): string[];
  create(o: object | null): any;
  defineProperty<T>(o: T, p: PropertyKey, ...): T;
  freeze<T>(a: T[]): readonly T[];
  freeze<T extends Function>(f: T): T;
  freeze<T>(o: T): Readonly<T>;
  // ...
}
  1. All instances of Object inherit all properties and methods of the Object interface:
function f(x: Object): { toString(): string } {
  return x; // OK
}
  1. Object type can also access all properties and methods defined on the object interface:
let bar: object = {};
bar.toString(); // "[object Object]"
bar.hasOwnProperty("abc"); // false
  1. Interestingly, due to the boxing and unpacking mechanism of JavaScript, basic types have the ability to access object Properties on prototype objects. Therefore, the TS Object type can accept both reference type and basic type (excluding undefined and null). However, the object type cannot accept the original value.
let b: Object = 1; // OK
let h: object = 1; // ERROR
  • iii. { }
  1. {} describes an Object without members. TS will throw an error when trying to access any of its properties. This type can also access all properties and methods on the Object type:
const obj: {} = {};
console.log(obj.name); // ERROR, there is no such attribute
obj.toString(); // "[object, Object]"
  1. {} can also be given an initial value:
let obj: {};
obj = 3; // OK
  1. Although both Object and {} can accept values of basic types, they do not include null and undefined:
let obj: {} = null || undefined; // ERROR
let obj: Object = null || undefined; // ERROR

To sum up, from a rigorous point of view, Object > Object > {}. The first two cannot be assigned to {}. Object is broad and general, {} is a broad but not completely general type. Object is the most rigorous type and is often used to constrain variables.
In terms of permission, {} > Object > object. The first two (including other basic types) can access the prototype properties of the object due to the existence of the disassembly box mechanism. Object can access properties other than values of the basic type. But {} is completely inaccessible.
Therefore, object should always be used when constraining object types. When defining object types, we should use {}. Use as few objects as possible.

1.11 Never type

The Never type represents the types of values that Never exist. For example, Never type is the type of return value of function expressions that always throw exceptions or have no return value at all:

function error(message: string): never {
  throw new Error(message);
}

function infiniteLoop(): never {
  while(true) {}
}

In TS, we can use the feature of never type to realize comprehensive inspection:

type IsStrNum = string | number;

function controlFlowAnalysisWithNever(str: isStrNum) {
  if (typeof str === "string") {
	// Narrow to string type
  } else if (typeof str === "number") {
	// Narrow to number type
  } else {
	const result: never = str;
  }
}

Note that in the else branch, we assign str narrowed to never to a never variable that displays the declaration. If all logic is correct, it should be able to compile here. But if one day your colleague changes the type of istrnum:

type IsStrNum  = string | number; => type IsStrNum  = string | number | boolean;

However, he forgot to modify the control flow in the controlFlowAnalysisWithNever method at the same time. At this time, the str type of else branch will be narrowed to boolean type, so that it cannot be assigned to never type. At this time, a compilation error will be generated. In this way, we can ensure that the controlFlowAnalysisWithNever method always exhausts all possible types of istrnum. Through this example, we can draw a conclusion: use never to avoid the new union type without corresponding implementation. The purpose is to write code with absolutely safe type.

So far, I've written about the basic data types in the basic chapter of TypeScript. I see here and ask you a question: how many data types are there in TypeScript? Leave your answers in the comments area.

Keywords: Javascript Front-end TypeScript

Added by phpscriptcoder on Tue, 15 Feb 2022 18:26:34 +0200