TypeScript数据类型

92 阅读5分钟

Boolean 类型

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

Number 类型

let count: number = 10;
// ES5:var count = 10;

String 类型

let name: string = "王尼玛";
// ES5:var name = '王尼玛';

Symbol 类型

const symbol = Symbol();
let obj = {
  [symbol]: "王尼玛",
};
console.log(obj[symbol]); // 王尼玛 

Array 类型

let list: number[] = [0, 1, 2];
// ES5:var list = [0, 1, 2];
let list: Array<number> = [0, 1, 2]; // Array<number>泛型语法
// ES5:var list = [0, 1, 2];

Enum 类型

使用枚举我们可以定义一些带名字的常量。 使用枚举可以清晰地表达意图或创建一组有区别的用例。 TypeScript 支持数字的和基于字符串的枚举。

1.数字枚举

enum Direction {
  FRIST,
  SECOND,
  THIRD,
}
let num: Direction = Direction.FRIST;

默认情况下,FRIST 的初始值为 0,之后的成员会从 1 开始自增。(Number.FRIST 的值为 0,Number.SECOND 的值为 1,Number.THIRD 的值为 2。)

以上的枚举示例经编译后,对应的 ES5 代码如下:

"use strict";
var Direction;
(function (Direction) {
  Direction[(Direction["FRIST"] = 0)] = "FRIST";
  Direction[(Direction["SECOND"] = 1)] = "SECOND";
  Direction[(Direction["THIRD"] = 2)] = "THIRD";
})(Direction || (Direction = {}));
var dir = Direction.FRIST;

当然我们也可以设置 FRIST 的初始值,比如:

enum Direction {
  FRIST = 10,
  SECOND,
  THIRD,
}

2.字符串枚举

在一个字符串枚举里,每个成员都必须用字符串字面量,或另外一个字符串枚举成员进行初始化。

enum Direction {
  FRIST = "FRIST",
  SECOND = "SECOND",
  THIRD = "THIRD",
}

以上代码对应的 ES5 代码如下:

"use strict";
var Direction;
(function (Direction) {
    Direction["FRIST"] = "FRIST";
    Direction["SECOND"] = "SECOND";
    Direction["THIRD"] = "THIRD";
})(Direction || (Direction = {}));

数字枚举除了支持 从成员名称到成员值 的普通映射之外,它还支持 从成员值到成员名称 的反向映射:

enum Direction {
  FRIST,
  SECOND,
  THIRD,
}

let dirKey = Direction[0]; // FRIST
let dirVal = Direction["FRIST"]; // 0

另外,对于纯字符串枚举,我们不能省略任何初始化程序。而数字枚举如果没有显式设置值时,则会使用默认规则进行初始化。

3.常量枚举

常量枚举是使用 const 关键字修饰的枚举,常量枚举会使用内联语法,不会为枚举类型编译生成任何 JavaScript。

const enum Direction {
  FRIST,
  SECOND,
  THIRD,
}
let dir: Direction = Direction.NORTH;

以上代码对应的 ES5 代码如下:

"use strict";
var dir = 0 /* NORTH */;

4.异构枚举

异构枚举的成员值是数字和字符串的混合:

enum Enum {
  A,
  B,
  C = "C",
  D = "D",
  E = 10,
  F,
}

以上代码对于的 ES5 代码如下:

"use strict";
var Enum;
(function (Enum) {
    Enum[Enum["A"] = 0] = "A";
    Enum[Enum["B"] = 1] = "B";
    Enum["C"] = "C";
    Enum["D"] = "D";
    Enum[Enum["E"] = 10] = "E";
    Enum[Enum["F"] = 11] = "F";
})(Enum || (Enum = {}));

数字枚举相对字符串枚举多了 “反向映射”:

console.log(Enum.A) //输出:0
console.log(Enum[0]) // 输出:A

Any 类型

任何类型都可以被归为 any 类型。这让 any 类型成为了类型系统的顶级类型(也被称作全局超级类型)。

let notSure: any = 666;
notSure = "王尼玛";
notSure = true;

any 类型本质上是类型系统的一个逃逸舱。 any 类型的值执行任何操作,无需事先执行任何形式的检查。

let value: any;

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

Unknown 类型

就像所有类型都可以赋值给 any,所有类型也都可以赋值给 unknown

let value: unknown;

value = true; // OK
value = 42; // OK
value = "Hello World"; // OK
value = []; // OK
value = {}; // OK
value = Math.random; // OK
value = null; // OK
value = undefined; // OK
value = new TypeError(); // OK
value = Symbol("type"); // OK

unknown 类型只能被赋值给 any 类型和 unknown 类型本身。

let value: unknown;

let value1: unknown = value; // OK
let value2: any = value; // OK
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

value 变量类型设置为 unknown 后,这些操作都不再被认为是类型正确的。通过将 any 类型改变为 unknown 类型,我们已将允许所有更改的默认设置,更改为禁止任何更改。

let value: unknown;

value.foo.bar; // Error
value.trim(); // Error
value(); // Error
new value(); // Error
value[0][1]; // Error
复制代码

Tuple 类型

元组可用于定义具有有限数量的未命名属性的类型。每个属性都有一个关联的类型。使用元组时,必须提供每个属性的值。

let tupleList: [string, boolean];
tupleList = ["王尼玛", true];

Void 类型

void 类型表示没有任何类型。当一个函数没有返回值时,你通常会见到其返回值类型是 void:

// 声明函数返回值为void
function init(): void {
  console.log("我要初始化了!");
}

以上代码编译生成的 ES5 代码如下:

"use strict";
function init() {
  console.log("我要初始化了!");
}

需要注意的是,声明一个 void 类型的变量没有什么作用,因为在严格模式下,它的值只能为 undefined

let unusable: void = undefined;

Null 和 Undefined 类型

TypeScript 里,undefinednull 两者有各自的类型分别为 undefinednull

let u: undefined = undefined;
let n: null = null;

object, Object 和 {} 类型

1.object 类型

object 类型用于表示非原始类型。

// node_modules/typescript/lib/lib.es5.d.ts
interface ObjectConstructor {
  create(o: object | null): any;
  // ...
}

const proto = {};

Object.create(proto);     // OK
Object.create(null);      // OK
Object.create(undefined); // Error
Object.create(1337);      // Error
Object.create(true);      // Error
Object.create("oops");    // Error

2.Object 类型

Object 类型:它是所有 Object 类的实例的类型,它由以下两个接口来定义:

  • Object 接口定义了 Object.prototype 原型对象上的属性;
// node_modules/typescript/lib/lib.es5.d.ts
interface Object {
  constructor: Function;
  toString(): string;
  toLocaleString(): string;
  valueOf(): Object;
  hasOwnProperty(v: PropertyKey): boolean;
  isPrototypeOf(v: Object): boolean;
  propertyIsEnumerable(v: PropertyKey): boolean;
}
  • ObjectConstructor 接口定义了 Object 类的属性。
// node_modules/typescript/lib/lib.es5.d.ts
interface ObjectConstructor {
  /** Invocation via `new` */
  new(value?: any): Object;
  /** Invocation via function calls */
  (value?: any): any;
  readonly prototype: Object;
  getPrototypeOf(o: any): any;
  // ···
}

declare var Object: ObjectConstructor;

Object 类的所有实例都继承了 Object 接口中的所有属性。

3.{} 类型

{} 类型描述了一个没有成员的对象。当访问这样一个对象的任意属性时,TypeScript 会产生一个编译时错误。

// Type {}
const obj = {};

// Error: Property 'prop' does not exist on type '{}'.
obj.prop = "semlinker";

但是,你仍然可以使用在 Object 类型上定义的所有属性和方法,这些属性和方法可通过 JavaScript 的原型链隐式地使用:

// Type {}
const obj = {};

obj.toString(); // "[object Object]"

Never 类型

never 类型表示的是那些永不存在的值的类型。 例如,never 类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型。

// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
  throw new Error(message);
}

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

使用 never 避免出现新增了联合类型没有对应的实现,目的就是写出类型绝对安全的代码。