TypeScript中的基本类型
类型声明:
-
类型声明是TS非常重要的一个特点;
-
通过类型声明可以指定TS中变量(参数、形参)的类型;
-
指定类型后,当为变量赋值时,TS编译器会自动检查值是否符合类型声明,符合则赋值,否则报错;
-
简而言之,类型声明给变量设置了类型,使得变量只能存储某种类型的值;
-
语法:
-
let 变量: 类型; let 变量: 类型 = 值; function fn(参数: 类型, 参数: 类型): 类型{ ... }
-
自动类型判断:
- TS拥有自动的类型判断机制
- 当对变量的声明和赋值是同时进行的,TS编译器会自动判断变量的类型
- 所以如果你的变量的声明和赋值时同时进行的,可以省略掉类型声明
类型:
| 类型 | 例子 | 描述 |
|---|---|---|
| number | 1, -33, 2.5 | 任意数字 |
| string | 'hi', "hi", hi | 任意字符串 |
| boolean | true、false | 布尔值true或false |
| 字面量 | 其本身 | 限制变量的值就是该字面量的值 |
| any | * | 任意类型 |
| unknown | * | 类型安全的any |
| void | 空值(undefined) | 没有值(或undefined) |
| never | 没有值 | 不能是任何值 |
| object | {name:'孙悟空'} | 任意的JS对象 |
| array | [1,2,3] | 任意JS数组 |
| tuple | [4,5] | 元祖,TS新增类型,固定长度数组 |
| enum | enum{A, B} | 枚举,TS中新增类型 |
1. number数字
TypeScript 和 JavaScript一样,所有的数字都是浮点数,并没有区分 int 、float 、 double等类 型,所有的数字都是number 。 number类型支持十进制、十六进制等,以及 NaN和Infinity等。
const decimal: number = 6;
const binary: number = 0b1010; // 10
const hex: number = 0xf00d; // 61453
const octal: number = 0o744;// 484
const big: bigint = 100n;// 表示一个bigint型
2. string字符串
使用string定义字符串类型的变量,支持常规的单引号和双引号,也支持ES6的模板字符串:
const name: string = 'axuebin'; // axuebin
const desc: string = `My name is ${name}`; // My name is axuebin
3. boolean
let isDone: boolean = false;
function hello(isBetterCode: boolean) {
// ...
return isBetterCode ? 'good' : 'bad';
}
const isBetterCode: boolean = true;
hello(isBetterCode); // good
举例,下面这两行代码分别返回什么:
new Boolean('') == false
new Boolean(1) === true
所以,如果这样声明了一个表示布尔值的变量,编译是不会通过的:
const isBetterCode: boolean = new Boolean(1);
// Type 'Boolean' is not assignable to type 'boolean'.
// 'boolean' is primitive, but 'Boolean' is a wrapper object. Prefer using
'boolean' when possible
因为 new Boolean 返回的是一个 Boolean 对象,而不是一个 boolean 值。
如果你想这样写,也都是可以的:
const isBetterCode: Boolean = new Boolean(1);
const isBetterCode: boolean = Boolean(1);
4. 字面量
也可以使用字面量去指定变量的类型,通过字面量可以确定变量的取值范围
let color: 'red' | 'blue' | 'black';
let num: 1 | 2 | 3 | 4 | 5;
5. void空
void 0;// undefined
在TypeScript中,void表示任何返回值的函数:
function hello(): void {
console.log('hello typescript');
}
6. never
function error(message: string): never {
throw new Error(message);
}
7. null和undefined空
const u: undefined = undefined; // undefined
const n: null = null; // null
需要注意的是:
undefined 类型的变量只能被赋值为undefined,null类型的变量只能被赋值为null。
不过你可以把undefined和null类型的变量赋给 void 类型的变量
8. object(没啥用)
const obj: object = {};
9. any任意值
无法确定类型的变量,我们就需要any这个类型。any类型的变量可以被赋予任意类型的值:
let number: any = 'one';
number = 1; //1
const me: any = 'axuebin';
console.log(me.name); // undefined 不会报错
这样是不会报错的。
当然,如果在编程阶段能够确定类型的话,尽量还是能够明确指定类型。
声明变量(没赋值)的时候,如果未指定类型,那么该变量会被识别为 any 类型,比如:
let number; // 相当于 let number: any;
number = 1; //1
需要注意的是,没赋值。如果声明变量的时候同时赋值了,就会进行类型推论。
10.类型推论
声明变量的时候,如果对变量进行赋值,如果该变量没有明确地指定类型, TypeScript 会推测出一个 类型。
let number = 'one'; // 相当于 let number: string = 'one';
number = 1; // Type '1' is not assignable to type 'string'.
如果只声明没有赋值,就是any。
11. unknown
let notSure: unknown = 4;
notSure = 'hello';
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
unknown 类型只能分配给 any 类型和 unknown 类型本身。
现在继续尝试:
let value: unknown
value.foo.bar // Error
value.trim() // Error
value() // Error
new value() // Error
value[0][1] // Error
unknown 类型在被确定为某个类型之前,不能被进行诸如函数执行、实例化等操作,一定程度上对类型进行了保护。
在那些将取得任意值,但不知道具体类型的地方使用
unknown,而非any。
12. array数组
在TypeScript中,数组通过 [类型 + 方括号] 来定义:
const me: string[] = ['jack', '27']; // 定义一个都是 string 的数组
const counts: number[] = [1, 2, 3, 4]; // 定义一个都是 number 的数组
// error
const me: string[] = ['jack', 27]; // Type 'number' is not assignable to type 'string'.
counts.push('5'); // Argument of type '"5"' is not assignable to parameter of type 'number'.
还有一种方式是使用泛型:
const counts: Array<number> = [1, 2, 3, 4]; // 使用泛型定义一个都是 number 的数组
关于泛型,后面会仔细说明,现在就知道有这么个东西。
如果对数组中的类型不确定,比较常见的做法就是使用any:
const list: any[] = ['axuebin', 27, true];
13. tuple元组
还有一种特殊的情况,如果我们需要定义一个已知元素数量和类型的数组,但是各个元素的类型不相同,可以使用 tuple元组来定义:
const me: [string, number, boolean] = ['axuebin', 27, true];
当我们想要在这个数组 push 一个新元素时,会提示 (string | number | boolean) ,这是表示元组 额外增加的元素可以是之前定义的类型中的任意一种类型。 (string | number | boolean) 称作联合类型。
14. eunm枚举
枚举是 TS 对 JS 标准数据类型的补充,Java/c等语言都有枚举数据类型,在 TypeScript 里可以这样定义一个枚举:
enum Animal {
Cat,
Dog,
Mouse,
}
const cat: Animal = Animal.Cat; // 0
const dog: Animal = Animal.Dog; //1
既然是 JavaScript 没有的,我们就需要知道一个枚举最终会被编译成什么样的 JavaScript 代码:
"use strict";
var Animal;
(function(Animal) {
Animal[Animal["Cat"] = 0] = "Cat";
Animal[Animal["Dog"] = 1] = "Dog";
Animal[Animal["Mouse"] = 2] = "Mouse";
})(Animal || (Animal = {}));
const cat = Animal.Cat; // 0
const dog = Animal.Dog; // 1
很容易看出,Animal 在 JavaScript中是变成了一个object,并且执行了以下代码:
Animal["Cat"] = 0; // 赋值运算符会返回被赋予的值,所以返回0
Animal[0] = "Cat";
// 省略 ...
// 最终的 Animal 是这样的
{
0: "Cat",
1: "Dog,
2: "Mouse",
Cat: 0,
Dog: 1,
Mouse: 2,
}
枚举最终会编译成双向键值对对象
enum Color {
Red,
Green,
Blue,
}
let c: Color = Color.Green;
enum Color {
Red = 1,
Green,
Blue,
}
let c: Color = Color.Green;
enum Color {
Red = 1,
Green = 2,
Blue = 4,
}
let c: Color = Color.Green;
字符串枚举,即一一映射
enum Person {
jack = '杰克',
anna = '安娜'
}
15. Symbol
每个Symbol()方法返回的值都是唯一的。
const sym1: symbol = Symbol()
const sym2: symbol = Symbol('foo')
const sym3: symbol = Symbol('foo')
console.log(sym2 === sym3) // false
Symbol() 作为构造函数是不完整的:
const sym = new Symbol() // TypeError
这种语法会报错,是因为从 ECMAScript 6 开始围绕原始数据类型创建一个显式包装器对象已不再被支持,但因历史遗留原因, new Boolean()、new String() 以及 new Number() 仍可被创建:
const symbol = new Symbol() // TypeError
const bigint = new BigInt() // TypeError
const number = new Number() // OK
const boolean = new Boolean() // OK
const string = new String() // OK
使用场景
-
当一个对象有较多属性时(往往分布在不同文件中由模块组合而成),很容易将某个属性名覆盖掉,使用
Symbol值可以避免这一现象,比如vue-router中的name属性。// a.js 文件 export const aRouter = { path: '/index', name: Symbol('index'), component: Index }, // b.js 文件 export const bRouter = { path: '/home', name: Symbol('index'), // 不重复 component: Home }, // routes.js 文件 import { aRouter } from './a.js' import { bRouter } from './b.js' const routes = [ aRouter, bRouter ] -
模拟类的私有方法
const permission: symbol = Symbol('permission') class Auth { [permission]() { // do something } }这种情况通过类的实例是无法取到该方法,模拟类的私有方法。
但是,TypeScript 是可以使用
private关键字的,所以这种方法可以在 JavaScript 中使用。 -
判断是否可以用
for...of迭代if (Symbol.iterator in iterable) { for(let n of iterable) { console.log(n) } } -
Symbol.prototype.descriptionconst sym: symbol = Symbol('imooc') console.log(sym); // Symbol(imooc) console.log(sym.toString()); // Symbol(imooc) console.log(sym.description); // imooc