TypeScript快速上手

1,357 阅读5分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情

我希望能够写出一篇短小而精悍的TypeScript快速上手教程,让人能够抓住TypeScript的核心内容,而不是只停留在基础阶段。

1.定义类型

项目中用的最多的就是定义数据类型了,也是我觉得最复杂的,不仅是要自己定义类型,有时候还要从别的npm中导入它的类型并使用,也是综合性比较高的操作。

TypeScript的内置类型有几种,number,string,boolean,null,undefined都挺简单的。

1.1 联合类型

如果一个类型,它可以是多种类型,比如定时器,初始值一般赋值为null,后面才赋值一个定时器; 或者是一个变量,它既可以赋值number,又可以赋值string,就可以用"|"来扩增类型。(NodeJS类型需要安装 @Types/node)

let timer: null | NodeJS.Timeout = null
timer = setInterval(() => {
  console.log('123'); 
},1000)

let a: number | string = 123
a = 'xx'

1.2 type类型别名

像上面那样写,如果要写的类型太长了,就可以用type来声明一个类型的别名,可以简化成以下结构:

type timeout = null | NodeJS.Timeout
let timer: timeout = null
timer = setInterval(() => {
  console.log('123'); 
},1000)

type shap = string | number
let a: shap = 123
a = 'xx'

看起来好像多写了一行代码,会麻烦一点,但实际做项目的时候,类型都是单独放在一个.d.ts类型文件里面的,然后再导入引用的,所以整体的结构就很简洁。

1.3 interface接口

1.3.1 定义对象Object

接口是来定义对象、类和函数的

interface Iobj {
    name:string
    age:number
}

let obj:Iobj = {
    name:'xx'age:4
}

但其实用类型别名也可以定义对象:

type Iobj = {
    name:string
    age:number
}

let obj:Iobj = {
    name:'xx'age:4
}

区别在于:

1.interface接口只能定义对象、类和函数,而type类型别名能够定义任何类型。

2.interface后面直接跟类型,而type类型别名要“=”号

3.interface可以多次定义,最终结果是合并。而type只能定义一次,并且合并类型用“&”扩展。

interface Iobj {
    name:string
}

interface Iobj {
    age:number
}

//等价于
interface Iobj{
    name:string
    age:number
}
type goodsName = {
    name:string
}
type goodsPrice = {
    price:number
}
type goods = goodsName & goodsPrice

用法在于这个类型已经是别人定义好的,或者是基础类型,然后你只能去扩展这个类型。

1.3.2 定义函数Function

定义函数的话,则是分为函数声明和函数实现。

//函数声明
function fn(params: number): void

//函数实现
function fn(params: number) {
  if(params>0) console.log(params);
}

也可以用interface接口实现函数定义

interface Ifn {
  (params:number):void
}

const  fn:Ifn= (params: number)=> {
  if(params>0) console.log(params);
} 
1.3.2.1 函数重载

实现一个函数,使其可以“精确”的根据输入参数的类型,返回相应的数据。比如输入的是字符串,则返回的数据是字符串。如果输入的是数字,则返回一些数字。

虽然用泛型可以实现,但使用时,得到的数据不是精确的数据,而是 string | number。这与预期不符。

image.png

function fn<T>(params: T) {
    if (typeof params === 'string') return 'xxx'
    return 123
}

fn('22')

此时就可以用函数重载实现,ts允许函数可以多次声明,只要最后一次是函数实现就行。

image.png

function fn(name: string): 'xxx'
function fn(name: number): 123
function fn(name: string | number) {
    if (typeof name == 'string') return 'xxx'
    return 123
}

fn('123')

1.3.3 定义类class

用类实现接口要用implements关键词来实现。

interface Iclass {
    name: string
    fn(params: number): void
}

class Dog implements Iclass {
    name: string
    constructor(name) {
        this.name = name
    }
    fn(params: number) {
        console.log(params)
    }
}

1.4 定义数组Array

类型+[]表示只能存放指定类型的数组,下面表示只能存放数字类型的数组,以此类推。当然也可以使用联合类型来定义一个既可以是number又可以是string的数组。

let arr:number[] = [7,8,9]
let arr: (string | number)[] = [123 ,'xx']

1.5 never穷尽性检查

如果遇到需要对变量的类型做判断再做操作的时候,就可以用never做穷尽性检查。never可以赋值给任何值,但是只有any和never可以赋值给never,说人话就是,你可以判断一个已知变量的类型,到最后类型都判断完时,再补赋值给never,如果该变量的类型有变化的时候,你就能及时检查到。

type atype = number | string

function fn(a: atype) {
  if (typeof a === 'number') {
    return a
  } else if (typeof a === 'string') {
    return a
  } else {
    const check: never = a
    return check
  }
}

如果给atype增加一个新的类型,则会报错。一定要把类型都判断完了,最后补一个never防止有新添加的类型。

image.png

1.6 unkonwn类型判断

unknown和never有点像,只不过never是用来做穷尽型检查的,也就是说你已经知道了变量是什么类型,然后再逐个排除。而unknown是不确定类型,你可以根据变量的不同类型做不同操作。

与上面相比,用never做穷尽性检查,需要知道变量的类型,再穷尽,所以需要提前定义类型。而unknown是不确定类型,无需提前定义类型。只不过unknown只能赋值给any和unkonwn,所以不能用unkonwn做穷尽性检查。

function fn(a: unknown) {
  if (typeof a == 'number') {
    return a
  } else if (a instanceof Object) {
    return a
  }
}

1.7 泛型类型

1.8 定义类class

1.9 命名空间namspace

1.10 定义外部变量

1.11 定义模块module

1.12

更新中...