一起养成写作习惯!这是我参与「掘金日新计划 · 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。这与预期不符。
function fn<T>(params: T) {
if (typeof params === 'string') return 'xxx'
return 123
}
fn('22')
此时就可以用函数重载实现,ts允许函数可以多次声明,只要最后一次是函数实现就行。
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防止有新添加的类型。
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
更新中...