一、概述
TypeScript 定义变量类型的语法格式:
let 变量名:变量类型 = 值;
但我们为某个变量定义了类型之后,改变了只能赋予指定类型的值,否则会报错。
二、原始数据类型
JavaScript 的类型分为两种:原始数据类型(Primitive data types)和对象类型(Object types)。
原始数据类型包括:boolean
、number
、string
、null
、undefined
以及 ES6 中的新类型 Symbol
。
// 1. 布尔类型
let isLogin: boolean = true;
// 2. 数值类型
let age: number = 18;
// 3. 字符串类型
let job: string = "前端工程师";
// 4. 空值:一般用于函数返回值为空的情况
function sayHello(): void {
console.log("Hello");
}
// 5. null & undefined
let u:undefined = undefined;
let n: null = null;
// 6. symbol
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
类型的变量没有什么大用,因为你只能为它赋予 undefined
和 null
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