一、概述

TypeScript 定义变量类型的语法格式:

  1. let 变量名:变量类型 = 值;

但我们为某个变量定义了类型之后,改变了只能赋予指定类型的值,否则会报错。

二、原始数据类型

JavaScript 的类型分为两种:原始数据类型(Primitive data types)和对象类型(Object types)。

原始数据类型包括:booleannumberstringnullundefined 以及 ES6 中的新类型 Symbol

  1. // 1. 布尔类型
  2. let isLogin: boolean = true;
  3. // 2. 数值类型
  4. let age: number = 18;
  5. // 3. 字符串类型
  6. let job: string = "前端工程师";
  7. // 4. 空值:一般用于函数返回值为空的情况
  8. function sayHello(): void {
  9. console.log("Hello");
  10. }
  11. // 5. null & undefined
  12. let u:undefined = undefined;
  13. let n: null = null;
  14. // 6. symbol
  15. let s = Symbol();

三、特殊类型

1. any

any 用来表示允许赋值为任意类型。我们在知道,在TS中,如果一个变量被赋予了一个类型,就不能再赋予其他类型的值了,如果为任意类型,则可以赋予任何类型的值。

let message: any;
message = "TypeScript是JavaScript的超集!";
message = 123;
message = false;
message.split(''); // 控制台输出:message.split is not a function

提示:

  • 变量如果在声明的时候,未指定其类型,那么它会被识别为任意值类型,一般用于获取DOM。
  • any 是 TypeScript 中的顶级类型,使用 any,基本上放弃了类型检查,因此开发中会引起不必要的麻烦。比如上述示例中,访问 split 方法抛出异常。所以,一般情况下不建议使用 any 类型。

2. unknown

unknown 是TypeScript 3.0中引入的,也被认为是顶级类型,但它更安全,与 any 一样,所有类型都可以分配给 unknown

let message: unknown;
message = "TypeScript是JavaScript的超集!";
message = 123;
message = false;
message.split(''); // TS语法检测:Object is of type 'unknown'.

可以发现,在使用 any 定义类型时,调用 split 方法并不会出发TS的语法检测,而使用 unknown 时,TS会捕捉到问题并予以提示。

3. void

某种程度上来说,void 类型像是与 any 类型相反,它表示没有任何类型。 当一个函数没有返回值时,你通常会见到其返回值类型是 void

function run():void {
    console.log("I'm running!");
}

声明一个 void 类型的变量没有什么大用,因为你只能为它赋予 undefinednull

4. never

never 类型表示的是永不存在的值得类型,比如:

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

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

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

四、联合类型

联合类型表示可以为变量定义多个类型,比如:

let age: number | string;
age = 10;
age = '10';

上述示例示例中,变量 age 被定义成联合类型,可以赋值 number 类型 或者 string 类型的值。

通常在使用 age 变量时,为了更安全的使用,我们可以通过如下方法判断其具体类型之后进行相应的操作。

五、类型断言

类型断言(Type Assertion)可以用来手动指定一个值的类型。语法形式如下:

  • <Value>Type
  • Value as Tpe

示例:

let _name: unknown = "木子李";
let len: number = (_name as string).length;
let len: number = (<string>_name).length;

六、类型推断

如果没有明确的指定类型,那么 TypeScript 会推断出一个类型。

let hello = "Hello, TypeScript!";
hello = 10; // Type 'number' is not assignable to type 'string'.

提示:如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成 any 类型而完全不被类型检查。

七、类型别名

类型别名用来给一个类型起个新名字:

// 为 string 类型定义别名 LString;
type LString = string;
// 定义变量,指定类型为 LString(实际为 string 类型)
let message: LString;

message = 'Are you ok?';
message = 10; // Type 'number' is not assignable to type 'string'.

类型别名对于一些联合类型或者复杂类型比较有用,可以使其更加简洁,比如:

// 定义用户类型
type UserType = {
    name: string;
    age: number;
    job: string;
}
// 定义年龄类型
type AgeType = string | number;

let user: UserType = {
    name: "Li-HONGYAO",
    age: 18,
    job: '前端工程师'
}
let age: AgeType = user.age;

八、字面量类型

type LoginType = "用户名" | "邮箱" | "手机号";
let _type: LoginType;
_type = "手机号";
_type = "邮箱";
_type = "用户名";
_type = "微信"; // Type '"微信"' is not assignable to type 'LoginType'.

上例中,我们使用 type 定了一个字符串字面量类型 _type,它只能取三种字符串中的一种。

注意,类型别名与字符串字面量类型都是使用 type 进行定义。

九、数组

let arr1: number[] = [1, 2, 3];
let arr2: (string | number)[] = [1, 'A', 2];
let arr3: Array<number> = [1, 2, 3];

提示:数组在声明时确定元素类型之后数组元素只能是对应的数据类型,除非将数组元素类型指定为 any

十、元祖(Tuple)

元组类型允许表示一个 已知元素数量和类型 的数组,各元素的类型不必相同:

let foo: [string, number];

foo = ["Li-HONGYAO", 18];
foo = [18, "Li-HONGYAO"]; // Type 'string' is not assignable to type 'number'.

解构元祖:

let [uname, age] = ["Li-HONGYAO", 18];
console.log(uname); // Li-HONGYAO
console.log(age); // 18