TypeScript中的常用的数据类型

126 阅读7分钟

常见的三种值类型

number(数字类型)

// 申明一个数字类型的值
let a: number
a = 10

//不仅可以给形参设置类型,还可以给返回值设定类型
let sum (numA: number, numB: number) :number{ 
  return numA + numB
}

string(字符串类型)

// 申明一个字符串类型的值
let b: string = 'hello'

boolean(布尔类型)

// 申明一个bool类型的值
let c: boolean = true

let typeBoolean: boolean
//虽然有该类型,但是TS也非常智能,在赋值时如未指定类型,则会自动识别类型。鉴于boolean只有两个值,个人建议省略

let typeFlag1 = true  
let typeFlag2 = false //均自动识别变量为boolean类型

PS:类型注释

冒号 + 类型的叫类型注释

即: string这种叫类型注释

其他常见类型

字面量类型

// 字面量进行类型申明(字面量:即就是这个值本身)
let aa: 10
// a修改为其他值就会报错
aa = 11

// 实际开发中很少这么用,但是我们可以这么用
// 申明一个变量等于男或者女
let sex: 'male' | 'female'
// 我们使用的时候就可以赋值其中一个值,赋值其他值就会报错
sex = 'male'
sex = 'female'
sex = 'hello'

联合类型

// | 线可以用来连接多个类型(联合类型)
// 联合类型的符号是  |
// 除了用在字面量中,常规的使用当中有的更多
let bb: boolean | number
bb = true
bb = 123
// 赋值字符串,就错了
bb = 'hi'

any类型(任意类型)

// 申明任意类型的数据
// any表示任意类型,一个变量设置为any后相当于对该变量关闭了TS的类型检测
let cc: any
cc = 123
cc = true
cc = 'hi'

// 隐式any,即申明,但是不设置类型,如下
let dd
dd = 123

unknown类型

// unknown 表示未知类型
let ee: unknown
ee = 123
ee = true
ee = 'hi'

any和unknown比较

// 那么any和unknown有什么区别呢?
// any可以赋值给任何变量
let ff: string
ff = cc
// unknown实际上就是一个类型安全的any
// unknown类型的变量不能直接赋值给其他变量
let gg: string
gg = ee
// 如何处理这种报错呢?
// 1.类型判断
if(typeof ee === 'string') {
    gg == ee
}
// 2.类型断言(意思是,ee就是一个string,你就放心用了)
gg = ee as string
gg = <string>ee

PS:类型断言

  • 断言语法
    • 1.变量 as 类型
    • 2.<类型>变量

void类型

// void用来表示空,以函数为例,表示没有返回值的函数
function fn():void {
    console.log(11111)
}

// never表示永远不会返回结果
function fn2(): never {
    throw new Error('出错了')
}

object类型

// object表示一个js对象
let obj: object
obj = {}
obj = function() {

}
// js中对象太多了,一般不像上面这样申明,那么我们在上面时候用这种形式呢?
// 比如我们申明一个变量,但是我们希望变量中包含某个值时
let obj2: {name: string}
// 这样是正确的
obj2 = {name: '景天'}
// 这样就会报错
obj2 = {}
// 写多了也会报错
obj2 = {name: '景天',age:18}

// 那么我们就是要age,而且age也不确定有没有,怎么写呢?
let obj3: {name: string,age?: number}
// 这样都正确
obj3 = {name: '景天'}
obj3 = {name: '景天',age:18}

// 但是实际开发中,我们还会有不确定有多少其他属性值,怎么处理呢?
let obj4: {name: string, [propName:string]:any}
// 这样的话,除了要求的值,其他随便写不写,写什么都无所谓了
obj4 = {
    name: '景天',
    age: 18,
    c: true
}

函数

// 如何设置函数的类型申明呢?
// 这表示函数两个参数,都是number类型,返回值也是number类型
let fn1: (a:number,b:number) => number
fn1 = function(n1,n2) {
    return n1 + n2
}

// 函数中使用另一种类型限制
// ): number是限制返回值的类型的
function add(a: number,b:number): string {
    return String(a + b)
}

数组

/*
    array,两种申明方式(这也是一种泛型的写法)
    1. 类型[]
    2. Array<类型>
*/
// 纯字符串数组
let arr: string[]
arr = ['a','b','c']
// 纯数字数组
let arr2: Array<number>
arr2 = [1,2,3]

元组

// tuple(元组):固定长度的数组
let yuanzu: [string,number]
yuanzu = ['111',222]

枚举

// enum: 枚举
// 申明一个枚举类
enum Gender {
    male = 1,
    female = 0
}

let hh: {name: string,gender: Gender}
hh = {
    name: '景天',
    gender: Gender.male
}

类型的别名

// 类型的别名
type myType = string
// 这相当于还是string
let ii: myType

// 但是这样的话,通常没什么意义,而我们用字面量类型的时候,有时候可以使用
type jjType = 1 | 2 | 3 | 4 | 5 | 6 
// 这样无论我们多少个地方使用,都可以直接用了
let jj: jjType
let kk: jjType
let ll: jjType

// 任何类型都可以有别名
// 比如object
type obj = {
    x:number,
    y:number
}

// 别名的扩展
// 一个新的obj1在上面的obj的基础上扩展
type obj1 = obj & {
    z: number
}

TS泛型

TS泛型是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的特性

泛型用法

在函数中使用泛型

function test <T> (arg:T):T{
  console.log(arg);
  return arg;
}
test<number>(111);// 返回值是number类型的 111
test<string | boolean>('hahaha')//返回值是string类型的 hahaha
test<string | boolean>(true);//返回值是布尔类型的 true

使用方式类似于函数传参,传什么数据类型,T就表示什么数据类型, 使用表示,T也可以换成任意字符串。

在接口中使用泛型

// 注意,这里写法是定义的方法哦
interface Search {
  <T,Y>(name:T,age:Y):T
}

let fn:Search = function <T, Y>(name: T, id:Y):T {
  console.log(name, id)
  return name;
}
fn('li',11);//编译器会自动识别传入的参数,将传入的参数的类型认为是泛型指定的类型

在类中使用泛型

class Animal<T> {
 name:T;
 constructor(name: T){
  this.name = name;
 }
 action<T>(say:T) {
   console.log(say)
 }
}
let cat = new Animal('cat');
cat.action('mimi')

泛型约束

使用接口约束泛型

interface Person {
  name:string;
  age:number;
}
function student<T extends Person>(arg:T):T {
  return arg;
}

student({name:'lili'});//类型 "{ name: string; }" 中缺少属性 "age",但类型 "Person" 中需要该属性
student({ name: "lili" , age:'11'});//不能将类型“string”分配给类型“number”
student({ name: "lili" , age:11});

数组泛型

let arr:Array =[1,2,3] === let arr:number[]=[1,2,3]

泛型工具类型

Partial

partial的作用就是将某个类型中的属性全部变为可选项?

interface Person {
  name:string;
  age:number;
}
function student<T extends Person>(arg: Partial<T>):Partial<T> {
  return arg;
}

Record

Record<K extends keyof any, T>的作用是将K中所有的属性转换为T类型;示例:

interface PageInfo {
  title: string
}
type Page = 'home'|'about'|'other';
const x: Record<Page, PageInfo> = {
  home: { title: "xxx" },
  about: { title: "aaa" },
  other: { title: "ccc" },
};

Pick

Pick<T, K extends keyof T>的作用是将某个类型中的子属性挑出来,变成包含这个类型部分属性的子类型,示例:

interface Todo {
  title:string,
  desc:string,
  time:string
}
type TodoPreview = Pick<Todo, 'title'|'time'>;
const todo: TodoPreview ={
  title:'吃饭',
  time:'明天'
}

Exclude

Exclude<T,U>的作用是将某个类型中属于另一个类型的属性移除掉,示例:

type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
const t:T0 ='b';

ReturnType

returnType的作用是用于获取函数T的返回类型,示例:

type T0 = ReturnType<() => string>; // string
type T1 = ReturnType<(s: string) => void>; // void
type T2 = ReturnType<<T>() => T>; // {}
type T3 = ReturnType<<T extends U, U extends number[]>() => T>; // number[]
type T4 = ReturnType<any>; // any
type T5 = ReturnType<never>; // any
type T6 = ReturnType<string>; // Error
type T7 = ReturnType<Function>; // Error

TypeScript高级类型

Partial

Partial 类型的定义

/**
 * Make all properties in T optional
 */
type Partial<T> = {
    [P in keyof T]?: T[P];
};

假设我们有一个定义 user 的接口,如下

interface IUser {
  name: string
  age: number
  department: string
}

经过 Partial 类型转化后得到

type optional = Partial<IUser>

// optional的结果如下
type optional = {
    name?: string | undefined;
    age?: number | undefined;
    department?: string | undefined;
}

Partial 可以快速把某个接口类型中定义的属性变成可选的(Optional):例子

interface People {
  age: number;
  name: string;
}

const Jerry:People = {
	age: 10,
	name: 'Jerry'
};

type AnonymousPeople = Partial<People>;

const tom:AnonymousPeople = {
	name: 'Tom'
};

Required

生成一个新类型,该类型与 T 拥有相同的属性,但是所有属性皆为必选项

// 源码
type Require<T> = {
    [p in keyof T]-?: T[P]
}

// 例子:
interface Foo {
    name: string
    age?: number
}
type Bar = Required<Foo>
// 相当于
type Bar = {
    name: string
    age: string
}

Readonly

生成一个新类型,T 中的 K 属性是只读的,K 属性是不可修改的

// 源码:
type Readonly<T> = {
    [p in keyof T]-?: T[P]
}

// 例子:
interface Foo {
    name: string
    age: number
}
type Bar = Readonly<Foo>
// 相当于
type Bar = {
    readonly name: string
    readonly age: string
}

Pick

生成一个新类型,该类型拥有 T 中的 K 属性集 ; 新类型 相当于 T 与 K 的交集

// 源码:
type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};

// 例子:
interface Foo {
    name: string;
    age?: number;
    gender: string;
}
type Bar = Pick<Foo, 'age' | 'gender'>
// 相当于
type Bar = {
    age?: number
    gender: string
}

const todo: Bar= {
   age?: 3,
   gender: 男
};
console.log(todo)

Omit

生成一个新类型,该类型拥有 T 中除了 K 属性以外的所有属性

// 源码:
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>> 

// 例子:
type Foo = {
	name: string
	age: number
}

type Bar = Omit<Foo, 'age'>
// 相当于
type Bar = {
	name: string
}

Exclude

如果 T 是 U 的子类型则返回 never 不是则返回 T

// 源码:
type Exclude<T, U> = T extends U ? never : T

// 例子:
type A = number | string | boolean
type B = number | boolean

type Foo = Exclude<A, B>
// 相当于
type Foo = string

Extract

和 Exclude 相反

// 源码:
type Extract<T, U> = T extends U ? T : never

// 例子:
type A = number | string | boolean
type B = number | boolean

type Foo = Extract<A, B>
// 相当于
type Foo = number | boolean