数据类型
一、基本类型
//字符串
let str: string = "Domesy"
// 数字
let num: number = 7
//布尔
let bool: boolean = true
//symbol
let sym: symbol = Symbol();
//bigint
let big: bigint = 10n
//null
let nu: null = null
//undefined
let un: undefined = undefined
- symbol是独一无二的,假设再定义一个 sym1,那么sym === sym1 为 false
二、引用类型
2.1 Array
定义数组方式有两种:
- 类型名称 + []
- Array<数据类型>
let arr1: number[] = [1, 2, 3]
let arr2: Array<number> = [1, 2, 3]
//要想是数字类型或字符串类型,需要使用 |
let arr3: Array<number | string> = [1, 2, '3']
2.2 Tuple(元组)
Tuple 的作用就是限制元素的类型并且限制个数的数组
let t: [number, string] = [1, '2']
// error
let t3: [number, string] = [1, '1', true]
// 只能通过 push 进行扩增
let t5: [number, string] = [1, '2'] // ok
t.push(2)
2.3 object(对象)
object 非原始类型,可以在定义上直接使用 object
let obj1: object = { a: 1, b: 2}
obj1.a = 3 // error
但你要更改对象的属性就会报错,原因是并没有使对象的内部具体的属性做限制,所以需要使用 {} 来定义内部类型
let obj2: { a: number, b: number } = {a: 1, b: 2}
obj2.a = 3 // ok
对象的类型标注
但在实际开发中,我们一半会用到 interface 来实现对象对外提供的接口结构。
interface User {
name: string;
age: number;
}
const user1: User = {
name: '张三',
age: 18
}
2.4 function
// 没有定义返回类型情况下 默认是 void,如果函数中有 return ,那么TS会自动推断
function setName1(name: string) {
console.log("hello", name)
}
// 定义返回类型
function setName2(name: string):string {
return name
}
- 支持 ? 实现可选参数
- 支持其它高级的 ES+ 语法,比如 = 设置默认值,使用扩展运算符 ...
三、特殊类型
3.1 any
在 TS 中,任何类型都可以归于 any 类型,所以any类型也就成了所有类型的顶级类型
let d:any
d = '1'
d = 1
// ...
3.2 unknow
与 any 一样,都可以作为所有类型的顶级类型,但 unknow 更加严格,那么可以说除了any 之下的第二大类型,接下来对比下 any ,主要严格于一下两点:
- unknow 会对值进行检测,而类型 any 不会做检测操作,说白了,any 类型可以赋值给任何类型,但 unknow 只能赋值给unknow类型和any类型
- unknow 不允许定义的值有任何操作(如 方法,new等),但any可以
let u:unknown = '1'
let str: string = u // error
3.3 void
当一个函数,没有返回值时,TS会默认他的返回值为 void 类型
3.4 never
表示一个函数永远不存在返回值,TS会认为类型为 never。那么与 void 相比, never应该是 void子集, 因为 void 实际上的返回值为 undefined,而 never 连 undefined也不行
符合never的情况有:当抛出异常的情况和无限死循环
let error = ():never => { // 等价约 let error = () => {}
throw new Error("error");
}
let error1 = ():never => {
while(true){}
}
四、装箱类型
Object(大写的O)是装箱类型,代表所有的原始类型或非原始类型都可以进行赋值,除了null和`undefined
let obj: Object;
obj = 1 // ok
obj = "a" // ok
obj = true // ok
obj = {} // ok
obj = Symbol() //ok
obj = 10n //ok
obj = null // error
obj = undefined // error
和 Object 类似的还有 Boolean、Number、String、Symbol,这几个装箱类型(Boxed Types) 同样包含了一些超出预期的类型。以 String 为例,它同样包括 undefined、null、void,以及代表的 拆箱类型(Unboxed Types) string,但并不包括其他装箱类型对应的拆箱类型,如 boolean 与 基本对象类型,我们看以下的代码:
const tmp9: String = undefined;
const tmp10: String = null;
const tmp11: String = void 0;
const tmp12: String = 'linbudu';
// 以下不成立,因为不是字符串类型的拆箱类型
const tmp13: String = 599; // X
const tmp14: String = { name: 'linbudu' }; // X
const tmp15: String = () => {}; // X
const tmp16: String = []; // X
在任何情况下,你都不应该使用这些装箱类型。
五、类型断言
有时候你很清楚改值是什么类型的时候,可以直接使用类型断言告诉编译器。这在开发时某些情况下很好用。
使用类型断言
let strLength: number = (<string>someValue).length
let strLength: number = (someValue as string).length
这里推荐使用 as 写法。
六、字面量类型
直接把值当作数据类型为字面量类型
const str: "zhangsan" = "zhangsan"
单一看字面量类型好像没什么用,一般会与联合类型一起使用。
七、联合类型
联合类型与枚举有点相似,就是列出特定的值,该变量的值只能从中获取。例如与上面的字面量类型相结合
interface User {
name: '张三' | '李四';
age: number
}
const user1: User = {
name: '张三',
age: 14
}
八、枚举
在 TypeScript 中通过 enum 来定义枚举数据
enum Direction {
Up = 'Up',
Down = 'Down',
Left = 'Left',
Right = 'Right',
}
console.log(Direction.Up) // Up
如果不指定值的话,那么默认就是从 0 开始递增
九、类型别名
类型别名起到的就是变量的作用,它可以存储一个类型,后续你可以直接引用它即可。
// 简单类型的类型别名
type myNumber = number
const time: myNumber = 10
// 对象类型的类型别名
type Uesr = {
name: string;
age: number;
}
const user: User = { /* ... */ }
注意:起别名不会新建一个类型 - 它创建了一个新名字来引用那个类型。给基本类型起别名通常没什么用。类型别名常用于联合类型。
十、交叉类型
交叉类型是将多个类型合并为一个类型。 这让我们可以把现有的多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性。
interface People {
name: '张三' | '李四'
age: number
}
interface Man {
header: string
body: string
}
const user: <People & Man> = {
name: '张三',
age: 21,
header: '圆头',
body: '强壮'
}