跳到主要内容

数据类型

一、number


const num: number = 20;
console.log(num);

二、string


const str: string = '小张';
console.log(str);

2.1 string vs String ?

  1. string 是 String 的类型表现,没有任何的方法和属性
  2. String 是一个构造函数,通过 Object、Number 类似,有着函数的方法和属性。

三、boolean


const bool: boolean = true;
console.log(bool);

四、undefined 和 null


默认情况下 nullundefined 是所有类型的子类型。 就是说你可以把 nullundefined 赋值给 number 类型的变量。

五、void


void表示没有任何类型,和其他类型是平等关系. void 不能直接赋值,所以一般用于函数返回值声明.

function fun(): void {
console.log('无返回数据');
}
fun();

六、symbol


const s1Symbol:symbol = Symbol('s1Symbol');
console.log(s1Symbol);

七、any


any类型是类型系统的顶级类型,动态的变量类型(失去了类型检查的作用)。any可以做为任何其他数据类型的父类(即 任何类型的值可以赋值给any),也可以作为任何其他数据类型的子类 (即 any类型的值也可以赋值给任何类型)。any 与 unknown 可以相互赋值

Typescriptany 类型的作用是什么?

为编程阶段还不清楚类型的变量指定一个类型。 这些值可能来自于动态的内容,比如来自用户输入或第三方代码库。 这种情况下,我们不希望类型检查器对这些值进行检查而是直接让它们通过编译阶段的检查。

any 作为任何其他数据类型的父类(即任何类型的值可以赋值给 any)
const bar:any = 123;
const bar1:any = "哈哈";
const bar2:any = false;
const bar3:any = {};
any 作为任何其他数据类型的子类
const bar:any = 123;
const bar1:any = "哈哈";
const bar2:any = false;
const bar3:any = {};

const b:number = bar;
const b1:string = bar1;
const b2:boolean = bar2;
const b3:object = bar3;
any 与 unknown 可以相互赋值
const bar4:any = '嘻嘻';
const b4:unknown=bar4;

const bar4:unknown = '嘻嘻';
const b4:any=bar4;
当 any 类型被赋值为一个对象时的特点:any 类型可以照常访问对象属性
const bar:any = {
name:'哈哈',
age:23
}

console.log(bar.name); // any 类型时,可以访问对象属性
console.log(bar.age); // any 类型时,可以访问对象属性

7.1 any vs unknown ?

  1. any 可以其他任何数据类型的父类,也可以作为其他任何数据类型的子类。而 unknown 可以作为其他任何数据类型的父类,但是不可以做为其他任何数据类型的子类。
  2. any 可以访问对象属性,unknown 不可以访问对象属性

八、unknown


unknown 类型是类型系统的顶级类型,在很多场景下,它可以替代 any 的功能同时保留静态检查的能力。unknown可以做为任何其他数据类型的父类(即 任何类型的值可以赋值给unknown),但是不也可以作为任何其他数据类型的子类 (即 unknown类型的值不可以赋值给任何类型)。any 与 unknown 可以相互赋值

unknown可以做为任何其他数据类型的父类(即 任何类型的值可以赋值给 unknown)
const bar:unknown = 123;
const bar1:unknown = "哈哈";
const bar2:unknown = false;
const bar3:unknown = {};
不也可以作为任何其他数据类型的子类 (即 unknown类型的值不可以赋值给任何类型)
const bar:unknown = 123;
const bar1:unknown = "哈哈";
const bar2:unknown = false;
const bar3:unknown = {};

const b:number = bar; // 报错 Type 'unknown' is not assignable to type 'number'
const b1:string = bar1; // 报错 Type 'unknown' is not assignable to type 'number'
const b2:boolean = bar2; // 报错 Type 'unknown' is not assignable to type 'number'
const b3:object = bar3; // 报错 Type 'unknown' is not assignable to type 'number'
any 与 unknown 可以相互赋值
const bar4:any = '嘻嘻';
const b4:unknown=bar4;

const bar4:unknown = '嘻嘻';
const b4:any=bar4;
当 unknown 类型被赋值为一个对象时的特点:unknown 类型不可以访问对象属性
const bar:unknown = {
name:'哈哈',
age:23
}

console.log(bar.name); // 报错 Object is of type 'unknown'.ts(2571)
console.log(bar.age); // 报错 Object is of type 'unknown'.ts(2571)

使用场景

  • 避免使用 any 作为函数的参数类型而导致的静态类型检查 bug

8.1 any vs unknown ?

  1. any 可以其他任何数据类型的父类,也可以作为其他任何数据类型的子类。而 unknown 可以作为其他任何数据类型的父类,但是不可以做为其他任何数据类型的子类。
  2. any 可以访问对象属性,unknown 不可以访问对象属性

九、never


never类型表示的是那些永不存在的值的类型。值会永不存在的两种情况:

  • 如果一个函数执行时抛出了异常,那么这个函数永远不存在返回值(因为抛出异常会直接中断程序运行,这使得程序运行不到返回值那一步,即具有不可达的终点,也就永不存在返回了);

    function err(msg: string): never { // OK
    throw new Error(msg);
    }
  • 函数中执行无限循环的代码(死循环),使得程序永远无法运行到函数返回值那一步,永不存在返回。

    function loopForever(): never { // OK
    while (true) {};
    }

9.1 什么情况下 never 可以直接被推导出来而不用被重新定义?

使用never避免出现未来扩展新的类没有对应类型的实现,目的就是写出类型绝对安全的代码。

type ParamsType = number | string;

function foo(params: ParamsType){
if(typeof params === 'string'){
console.log('字符串');
}else if(typeof params === 'number'){
console.log('数字');
}else{
let data = params; // data 就是 never 类型
}
}

十、object


10.1 动态对象属性

const map = {
stable:'……',
pre:'……',
online:'……'
}
const env:"stable"|"pre"|"online" = 'stable';
const url = map[env];

10.2 严格限制对象属性

interface Obj {
name:string;
age:number;
}
const obj:Obj = {
name:'柏拉图',
age:23
}

10.3 允许对象增加属性

interface Obj {
name:string;
age:number;
[key:string]:string;
}
const obj:Obj ={
name:'柏拉图',
age:23,
sex:'男'
}

10.4 对象解构赋值

type ObjectType = {
name: string;
age: number;
sex: string;
}

const { name, age }: ObjectType = {
name: '哈哈哈',
age: 23,
sex: '男'
}

10.5 设置对象 key 类型

const object = {
name:"哈哈",
age:23
}
type ObjectKeyType = keyof typeof object; // "name" | "age"
const bar:ObjectKeyType = "name"

十一、array


TypeScript数组是具有连续存储位置相同数据类型元素的同质集合。TypeScript 有两种声明数组的方法:

11.1 使用方括号声明数组

一维数组
const array: (string | number)[] = ['小', '张', 3];
console.log(array);
二维数组
const array: (string | number)[][] = [['哈哈', '嘻嘻', 3]];
console.log(array);

11.2 使用泛型声明数组

一维数组
const array : Array<string|number> = ['哈哈','嘻嘻',3];
console.log(array);

11.3 使用 type 声明数组

type ArrayType = {
[index:number]:number
}

const array:ArrayType = [10,20,30];

11.4 使用 interface 声明数组

interface ArrayInterface {
[index:number]:number
}

const array:ArrayInterface = [10,20,30];

十二、tuple


元组(tuple)TypeScript中特有的类型,其工作方式类似于数组。元组最重要的特性是可以限制数组元素个数类型,它特别适合用来实现多值返回。所以元祖用于保存定长****定数据类型的数据

一维数组
const array : [string,string,number] = ['哈哈','嘻嘻',3];
console.log(array);
二维数组
const array : [number,string][] = [[3,'哈哈'],[4,'嘻嘻']];
console.log(array);

12.1 tuple

元祖用于保存定长****定数据类型的数据,但是如果遇到一部分定长、定类型,之后得部分任意不确定时该怎么办呢?这时候就需要用到可变元组

头几个元素定长、定数据类型,后续元素随意
const array:[number,string,number,...any[]] = [1,'柏拉图',1,'男','越努力,越幸运']
console.log(array);
头几个元素定长、定数据类型,中间元素随意,末尾元素定定长、定数据类型
const array:[number,string,number,...any[],string] = [1,'柏拉图',1,'男','越努力,越幸运','呵呵,我是末尾']
console.log(array);

12.2 tuple

const array1: [number, string, string] = [1, '柏拉图', '男'];
const array2: [id: number, name: string, sex: string] = [1, '柏拉图', '男'];


const array3: [number,string,string,...any[]] = [1,'柏拉图','男','呵呵','呵呵']
const array4: [id:number,name:string,sex:string,...rest:any[]] = [1,'柏拉图','男','呵呵','呵呵']
const array5: [id:number,name:string,sex:string,...rest:any[],description:string] = [1,'柏拉图','男','呵呵','呵呵','我是末尾元素']

十三、enum


TypeScript 枚举用于定义一组命名常量,即一组相关值.TypeScript支持数字枚举字符串枚举.我们可以使用enum关键字定义枚举。

为什么要使用枚举? 为了解决多次 if/switch 判断语句中值的语义化的问题

  • 之前的解决方式常量解决 ,但是这种方式不能定义为具体类型,只能定义为 number 、 string 等基本数据类型,降低了代码的可读性和可维护性。
  • 现在的解决方式枚举解决,有默认值和可以自增值,节省编码时间。并且语义更清晰,可读性强。

13.1 数字枚举

数字枚举是基于数字的枚举,将值存储为数字。数字枚举 可以通过key访问value,也可以通过value访问key数字枚举 在编译阶段被编译成一个对象,包含双向映射key -> value)和(value -> key),因此可以从枚举值到枚举名进行反向映射。引用枚举成员总会生成一次属性访问并且永远不会内联

省略初始化,元素值从0开始自动递增
enum Status {
pending,
fulfilled,
rejected
}

console.log(Status['pending']); // 0
console.log(Status[0]); // pending
初始化第一个元素,后续元素值自动递增
enum Status {
pending = 1,
fulfilled,
rejected
}

console.log(Status['pending']); // 1
console.log(Status[1]); // pending
枚举值全部初始化
enum Status {
pending = 4,
fulfilled = 8,
rejected = 12
}

console.log(Status['pending']); // 4
console.log(Status[4]); // pending
计算枚举值,常熟表达式的结果必须是一个常数,如果结果为 NaN 或者 Infinity ,则会在编译阶段报错。
enum Direction{
up,
down,
left,
right
}
enum Status{
a = 3+4,
b = 4*5,
c = "哈哈哈".length,
d = Direction['up'],
}

let statusList = [Status['a'],Status['b'],Status['c']];
console.log(statusList);

13.2 字符串枚举

字符串枚举是基于字符串的枚举,将值存储为字符串. 但是枚举值不具有自动递增的行为。字符串枚举 可以通过key访问value字符串枚举 在编译阶段被编译成一个对象,包含单向映射key -> value)因此字符串枚举仅仅是以从枚举名到枚举值的单向映射。引用枚举成员总会生成一次属性访问并且永远不会内联

enum TypeMap {
a='A',
b="B",
c="C"
}

console.log(TypeMap['a']);

13.3 异构枚举

enum TypeMap {
a='A',
b="B",
c="C",
left=1,
}

console.log(TypeMap['a']);

13.4 常数枚举


常数枚举只能使用常数枚举表达式。并且不同于常规的枚举的是它们在编译阶段会被删除,因此常熟枚举没有双向映射常数枚举成员在使用的地方被内联进来。 这是因为常数枚举不可能有计算成员常熟枚举 可以避免生成多余的代码间接引用

const enum Status{
pending,
fulfilled,
rejected
}

let statusList = [Status['pending'],Status['fulfilled'],Status['rejected']];
console.log(statusList);