美文网首页
TypeScript(二) 常见数据类型

TypeScript(二) 常见数据类型

作者: 梦晓半夏_d68a | 来源:发表于2022-12-24 01:05 被阅读0次
image-20200528172415100

注: symbol 为ES6中新增类型

类型

  1. string /boolean /number
// 字符串:支持es6 拼接
let sport:string = '足球'
let hobby:string;
hobby = `我爱${sport}` // 支持es6 拼接 ``
console.log( hobby)

// 布尔值
let choice:boolean = false

// 数值: 和JavaScript一样,TypeScript里的所有数字都是浮点数。支持二进制、八进制、十进制、十六进制、整数和小数(整数可以算进十进制)、NaN(非数字)、Infinity(无穷大)
let binNum:number = 0b110 // 二进制
let octNum:number = 0o6 // 八进制
let num:number =  6// 十进制
let hexNum:number = 0x6 // 十六进制
let maxNum:number = Infinity // 无穷大
let isNaNum:number = NaN // 非数值

注意:
(1)这里的string是小写的,和String是有区别的
(2)使用构造函数(BooleanStringNumber)创造的对象并不是布尔值,而是返回一个对象。直接调用Boolean() 则返回一个布尔值,常用于将一个值强制转换为boolean类型,在此我以构造函数 Boolean 为例:

let isBoolean:boolean = new Boolean(1) // 报错'boolean' is a primitive, but 'Boolean' is a wrapper object. Prefer using 'boolean' when possible.
let isBoolean:boolean = Boolean(1) // true
  1. array 数组
  • 特点
    元素类型限制,长度不限制

方式1:类型[]

let array: number[] = [1, 2, 3, 4];

数组的一些方法的参数也会根据数组在定义时约定的类型进行限制:

array.push('2');
// 报错:Argument of type 'string' is not assignable to parameter of type 'number'

方式2:Array<类型>
(Array Generic) 数组泛型表示数组

let array: Array<number> = [1, 2, 3, 4];

自己写数组泛型

方式3:接口(不推荐)
数组的索引就是 number 类型的 0,1,2,3..., JS 中数组是一类特殊的对象,特殊在数组的键(索引)是数值类型
MyArray 接口模拟原生的数组接口,并使用 [n: number]来作为索引签名类型。

interface MyArray<T> {
  [index:number]: T
}
const testArray: MyArray<string> = ["1", "2", '3']
const testArray2: MyArray<number> = [1, 2, 3]

类数组:
类数组不是数组,使用数组的类型会报错

function add() {
    let args: number[] = arguments;
}
// 报错:Type 'IArguments' is missing the following properties from type 'number[]': pop, push, concat, join, and 26 more.

arguments 为类数组,应该使用下面这种方式定义类型

function sum() {
    let args: {
        [index: number]: number;
        length: number;
        callee: Function;
    } = arguments;
}

其实常用的类数组都有自己的接口定义,如 IArguments, NodeList, HTMLCollection 等

function add() {
    let args: IArguments = arguments;
}
  1. tuple 元组
  • 语法

let 元组名:[类型1,类型2,类型3] = [值1, 值2,值3]

  • 使用
let tup1:[number, string, boolean] = [1, '3', true]

当直接对元组中的变量进行初始化的时候,变量的数量及变量对应的类型必须与类型指定一致 ,否则报错

let tup1:[number, string, boolean] = [1, '3', true]
let tup2:[number, string, boolean] = [1, '3'] // Property '2' is missing in type '[number, string]' but required in type '[number, string, boolean]'.
let tup3:[number, string] = [1, 3] // Type 'number' is not assignable to type 'string'.

需要注意元祖的越界问题,虽然可以越界添加元素,但是不能越界访问,强烈不建议这么使用,而且越界的元素的类型会被限制为元组中每个类型的联合类型:

let tom: [string, number];
tom = ['Tom', 25];
tom.push('male');
tom.push(true);
// Argument of type 'boolean' is not assignable to parameter of type 'string | number'
let tup4:[string, number] = ['1', 3]
tup3[0] = 'Tom'
tup3.push('apple')
console.log(tup3) // ["Tom", 3, "apple"]
console.log(tup3[2]) // Tuple type '[string, number]' of length '2' has no element at index '2'
  • 特点

长度限制,每个元素的类型限制,但不同元素类型可不同
其实,可以和数组进行对比理解:
数组是合并了相同类型的对象,而元组(Tuple)则是合并了不同类型的对象,且类型和数量已定

  1. enum 枚举
  • 语法

enum 枚举名{
枚举项1 = 值1,
枚举项2 = 值2 ...
}

注:枚举项名称一般由英文和数字组成,值一般用数字,默认为0,1,2...

  • 使用

    默认情况下是从0开始为元素编号

enum gender1 {
  male,
  female,
  unkown
}
console.log(gender1.male) // 0

也可以手动的部分指定成员的数值或全部,后面的成员一次加1

enum gender2 {
  male,
  female = 2.5,
  unkown
}
console.log(gender2.male) // 0
console.log(gender2.unkown) // 3.5
  • 特点
    长度限制,每个元素的类型限制,但不同元素类型可不同
    可以理解为:定了元素类型和数量的数组,但多个元素类型可不同
  1. any 任意类型
    一般来说,如果一个变量赋值为某个类型,在赋值过程中是不允许改变类型的,但是any 类型除外,允许被赋值为任意类型。

    any类型 一般用在不清楚变量的类型的情况。 在这种情况下,不想让类型检查器对这些值进行检查。 就可以使用 any类型来标记这些变量

  • 语法

let 变量名: any;

用来表示允许赋值为任意类型。

  • 使用
let anyThing1:any
anyThing1 = 'dd'
anyThing1 = 123

let anyThing2: any[] = [1, true]
anyThing2.push('222')
anyThing2[1] = undefined
console.log(anyThing2) // [1, undefined, "222"]

如果变量在声明的时候未指定其类型,那么它会被识别为任意值类型:

let something;  // 等同于var something:any;
something = 'seven';
something = 7;
console.log(something); // 7
  1. void

没有任何类型,从一定角度可以认为void类型与any类型相反。但是在写代码的过程中一般不会单独声明一个void类型的变量,因为其只能赋值undefinednull,意义不大

let unusable: void = undefined;

void一般用在当一个函数没有返回值时,设置返回值类型为 void

function sayHi(): void {
    console.log("Hi,everyone");
}
  1. null和undefined

undefinednull 都有自己的类型,分别为undefinednull 。但是这并没有多大意义。

let undefType:undefined = undefined
let nullType:null = null

默认情况下nullundefined是所有类型的子类型。 就是说你可以把 nullundefined赋值给其他类型的变量,但是如果设置了--strictNullChecks 严格的空校验 ,nullundefined只能赋值给void和自身。 在写代码的过程中建议开启空校验。 如果某个变量的类型可能为 numbernullundefined,建议使用联合类型number | null | undefined

  1. never类型

表示永不存在的值的类型,一般用作抛出异常或无限循环的函数返回类型。

function test():never{
    while (true){
        ...
    }
}
function test2():never{
    throw new Error('Error');
}

never 类型是ts中的底部类型,是所有类型的子类型,因此可以赋值给任何类型变量

let cat:string = test()
  1. 联合类型

在实际写代码的过程中,有时候定义的变量的类型可能是多种的,因此联合类型便派上用场了。

  • 语法

let 变量名:类型1|类型2... = 值

  • 使用
let info:string|null|number;
info = 22
info = '你好吗'
info = null

let infoArr:(string|number)[];
infoArr = [12, 'sad', 222]

当不确定变量是哪个类型的时候,只能访问此联合类型的所有类型里共有的属性或方法

let temp:(string|number|boolean);
console.log(temp.length) // Property 'length' does not exist on type 'number'.

9.交叉类型
类似于接口继承,用于组合多个类型为一个类型(常用于对象类型)

interface Person { name: string }
interface People { sex: string }
type PersonMan = Person & People

相当于:

type PersonMan  = {name: string, sex: string }

当交叉的类型里有相同属性时

   interface Person {
      name: string;
      title: string | number;
    }
    interface People {
      name: number;
      sex: string;
      title: string;
    }
    type PersonMan = Person & People;
    let dan: PersonMan = {
      name: 'ww', // name 报错:Type 'string' is not assignable to type 'never'.
      sex: 'girl',
      title: 'title',
    };

name 类型推导结果是 never,因为不存在一个值既是 string 又是 number 的。
title 类型推导结果是 string

总结:
交叉类型算的是 2 个类型的 并集。就是双方都有的东西才能合并到一起,不一样的将会被排除
如果排除到最后都没有相同的东西,那么就会变 never 类型(即该类型不存在)
内置类型(string,number,boolean,unio 联合类型)之间可以使用 &

  1. 映射类型
    参考
    映射类型是指基于现有类型产生新的类型
    通过遍历语法拷贝原有类型 在拷贝类型的基础上进行修改从而产生新的类型
    语法:
{[P in K]: T} 

Partial 将每个属性转换为可选属性

type Partial<T> = {
    [P in keyof T]?: T[P];
}
type PersonPartial = Partial<Person>;

Readonly 将每个属性转换为只读属性

type Readonly<T> = {
    readonly [P in keyof T]: T[P];
}
type ReadonlyPerson = Readonly<Person>;

Pick 选取一组属性指定新类型

type Pick<T, K extends keyof T> = {
  [P in K]: T[P];
}
interface Todo {
  title: string;
  description: string;
  completed: boolean;
}

type TodoPreview = Pick<Todo, "title" | "completed">;

const todo: TodoPreview = {
  title: "Clean room",
  completed: false,
};

Exclude 去除交集,返回剩余的部分

type Exclude<T, U> = T extends U ? never : T
interface Props {
  a?: number;
  b?: string;
}

const obj: Props = { a: 5 };

const obj2: Required<Props> = { a: 5 };
Property 'b' is missing in type '{ a: number; }' but required in type 'Required<Props>'

Nullable 转换为旧类型和null的联合类型

type Nullable<T> = { 
  [P in keyof T]: T[P] | null 
}
type NullablePerson = Nullable<Person>;

Omit 适用于键值对对象的Exclude,去除类型中包含的键值对

type Omit = Pick<T, Exclude<keyof T, K>>
interface Todo {
  title: string;
  description: string;
  completed: boolean;
}

type TodoPreview = Omit<Todo, "description">;

const todo: TodoPreview = {
  title: "Clean room",
  completed: false,
};

Required 将每个属性转换为必选属性

type Required<T> = {
  [P in keyof T]-?: T[P]
}
interface Props {
  a?: number;
  b?: string;
}

const obj: Props = { a: 5 };

const obj2: Required<Props> = { a: 5 };
  1. 接口
interface Person {
    name: string;
    age: number;
}

let tom: Person = {
    name: 'Tom',
    age: 25
};

接口一般首字母大写。
注意:定义的变量比接口多或者少了一些属性是不允许的:

可选属性

interface Person {
    name: string;
    age?: number;
}

let tom: Person = {
    name: 'Tom',
    age: 25
};

建议:书写的时候可选属性建议放在最后

任意属性

interface Person {
    name: string;
    age?: number;
    [key: string]: any;
}

let tom: Person = {
    name: 'Tom',
    gender: 'male'
};

注意:一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集

interface Person {
    name: string;
    age?: number;
    [key: string]: string;
}

let tom: Person = {
    name: 'Tom',
    age: 25,
    gender: 'male'
};

// 报错:Property 'age' of type 'number' is not assignable to 'string' index type 'string'.

一个接口中只能定义一个任意属性。如果接口中有多个类型的属性,则可以在任意属性中使用联合类型:

interface Person {
    name: string;
    age?: number;
    [key: string]: string | number;
}

建议:实际开发中不要使用过多的任意类型,使用到什么属性就把对应的类型添加到接口里即可。

只读属性
如果只希望对象中的一些字段只能在创建的时候被赋值,那么可以用 readonly 定义只读属性:


// interface Person {
    readonly id: number;
    name: string;
    age?: number;
    [propName: string]: any;
}

let tom: Person = {
    id: 89757,
    name: 'Tom',
    gender: 'male'
};

tom.id = 9527;

// 报错:Cannot assign to 'id' because it is a read-only property.
  1. 字符串字面量
    字符串字面量类型用来约束取值只能是某几个字符串中的一个。
type EventNames = 'click' | 'scroll' | 'mousemove';

相关文章

网友评论

      本文标题:TypeScript(二) 常见数据类型

      本文链接:https://www.haomeiwen.com/subject/tfmiqdtx.html