Skip to content
目录

基础篇-数据类型

JavaScript 数据类型
String、Number、Boolean、Object(Array、Function)、Symbol、undefined、null

TypeScript 新增数据类型
void、any、never、元组、枚举、高级类型

类型注解

作用: 相当于强类型语言中的类型声明

语法:(变量/函数): type

字符串类型 string

js
let name: string = 'hello TS';
let years: number = 2019;
let words: string = `${name}今年是 ${number}`;

数字类型 number

数字类型,不区分整形与浮点,所有数字均当作浮点数字对待。同时也支持二进制,八进制,十六进制数字。

js
let decimal: number = 6;
let hex: number = 0xf00d;
let binary: number = 0b1010;
let octal: number = 0o744;

布尔类型 boolean

js
let isEmployee: boolean = false;
function hasPermission(role: string): boolean {
  return role === 'admin' ? true : false;
}

数组类型 array

数组本身是容器,需要上面的基本类型联合使用,定义有两种方式。

js
//方式一:
let names: Array<string>; // 字符串数组
let nums: Array<number>; // 存放数字的数组
let data: Array<any>; // 数组中各元素类型不确定
//方式二:
let names: string[]; // 字符串数组
let nums: number[]; // 存放数字的数组
let data: any[]; // 数组中各元素类型不确定

元组类型 tuple

元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。 比如,你可以定义一对值分别为 string 和 number 类型的元组。

当数组中元数个数有限且提前知晓每个位置的类型时,可将这种数据声明成元组(tuple,如果你用过 Python 应该不会陌生)。

js
let point: [number, number] = [7, 5]; //元祖类型
let x: [string, number] = ['hello', 10]; //元祖类型

当访问一个已知索引的元素,会得到正确的类型:

js
console.log(x[0].substr(1)); // OK
console.log(x[1].substr(1)); // Error, 'number' does not have 'substr'

当访问一个越界的元素,会使用联合类型替代:

js
x[3] = 'world'; // OK, 字符串可以赋值给(string | number)类型
console.log(x[5].toString()); // OK, 'string' 和 'number' 都有 toString
x[6] = true; // Error, 布尔不是(string | number)类型

枚举类型 enum

枚举类型在强类型语言中是很常见的,用来标识变量可取的候选值。

js
enum Gender {
    Male,
    Female
}
console.log(Gender.Female===1); // true

枚举实质上是通过更加语义化的符号来表示数字类型的值,比如上面 Gender.Female 代表的值是 1,因为枚举默认从 0 开始。 可通过手动指定的方式来改变默认的 0

js
enum Gender {
    Male = 1,
    Female
}

console.log(Gender.Female); // 2

当然,你也可以让枚举表示其他类型的值,而不是数字。只不过需要手动指定。

如果手动指定非数字类型的值,那么枚举中的项是无法像数字那样自动自增以初始化自己,所以需要手动为每个项都显式指定一下它应该代表的值。

js
enum Gender {
    Male = "male",
    Female // 🚨 Enum member must have initializer.
}

正确的做法:

js
enum Gender {
    Male = "male",
    Female = "female" // ✅
}

console.log(Gender.Female); // female

枚举中的值也不一定都得是同一类型,所以下面这样也是可以的:

js
enum Gender {
    Male = "male",
    Female = 2 // ✅also ojbk
}
console.log(Gender.Female); // 2

空值类型 void

常见于函数没有返回值的情况。

js
/** () => void */
function warnUser(): void {
  console.log('This is my warning message');
}

如果将变量显式设置为 void,没有多大实际意义。
因为变量始终是要用来承载有用的值的,如果你发现有这种需要,可使用 null|undefiend 代替。

js
let unusable: void = undefined;

null 和 undefined

两者其实是其他任意类型的子类型。比如,一个变量定义后没有初始化,此时其值自动为undefined。这说明,undefined 是可以赋值给这个类型的。当我们想把变量的值取消,将其置空时,可将其设置为 nullnull也是可以赋值给其他类型变量的,前提是 tsconfig.json 中没有开启 strict:true

js
let age: number;
console.log(age); // undefined

age = 9;
console.log(age); // 9

age = null;
console.log(age); // null

当开启strict:true 强制检查后,TypeScript 会对类型进行严格的检查。上面就不能在未初始化的情况下使用变量,同时也不能将 null 赋值给 number 类型。
对于这两种类型,在强制检查下,除非显式对变量进行声明其可空可未初始化

js
let age: number | null | undefined;
console.log(age); // undefined

age = 9;
console.log(age); // 9

age = null;
console.log(age); // null

这里number | null | undefined是一个组合类型(union type),后面会有提到。
一般来说,建议开启强制检查,这样 TypeScript 能够最大化帮我们发现代码中的错误,在写码时就发现问题。

never 类型

never 是其它类型(包括 null 和 undefined)的子类型,代表从不会出现的值。

这意味着声明为 never 类型的变量只能被 never 类型所赋值,在函数中它通常表现为抛出异常或无法执行到终止点(例如无限循环),示例代码如下:

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

// 推断的返回值类型为never
function fail() {
  return error('Something failed');
}

// 返回never的函数必须存在无法达到的终点
function infiniteLoop(): never {
  while (true) {}
}

Symbol

symbol 类型的值是通过 Symbol 构造函数来创建

js
let s: symbol = Symbol();

ES6 Symbol

任意类型 any

声明为 any 的变量可以赋予任意类型的值,此时等同于普通的 JavaScript 代码,因为标记为 any 后将会跳过 TypeScript 的类型检查。

js
let someVar: any;
someVar = '字符串'; // ✅
someVar = 99; // ✅
someVar = undefined; // ✅
someVar = null; // ✅

即便在开启强制检查的情况下,上面的操作是没有任何问题的。一般情况下,只在一些特殊情况下使用 any,比如老代码的兼容,三方库代码的引入。

js
declare var $: any;

$.extenfd({}, { foo: 'foo' });

这里,因为 jQuery 是没有类型的三方库代码,但我们知道页面中引入后是可以调用它上面的方法的,只是 TypeScript 不识别,所以我们通过声明一个 any 类型的变量来快速解决这个问题。