共计 3737 个字符,预计需要花费 10 分钟才能阅读完成。
为什么要用 typescript
增加了类型,避免了诸如函数调用传错参数的低级错误:
提供了代码提示:
如何使用
npm install typescript -g tsc
这里需要说明一下的是,typescript
是一个泛指,包括语言特性和语言相关的生态功能。要不然看官方的更新文档,就会有困惑,有很多明显不属于 typescript语言 的更新,比如重命名的时候对应的函数或文件跟着自动变了这种功能,很明显不属于语言的特性,应该是编辑器或者 IDE 负责的东西,咋就放到语言的更新日志里了呢?
从一个例子说起
来,我们看个例子:
function add(a:number, b:number):number {return a+b}
上面的代码,我们声明了一个 add
函数,接收两个参数 a 和 b,告诉编辑器和调用 add 函数的人,“这俩参数都是 number 类型,别传错参数啊,对了,我这个函数的返回值也是一个 number 类型,别指望我给你返回其他东西”。
我们可以看出,和 JS 最大的区别就是,增加了类型。
类型可以用在哪里
我们上面的例子里,类型
用来标注函数的参数的类型、函数的返回值类型。此外也可以用来表示一个变量的类型。
比如:
var a:number=1
上面的代码的意思是,声明里一个变量 a,这个变量 a 的类型是 number 类型。由于 typescript 的 类型推断
功能,我们上面的代码也可以写成这样:
var a=1
ts 编译器看到后面的数字 1 之后,会智能的推断的出 a 是一个 number 类型,是不是发现 ts 还是很聪明的嘛
都有哪些类型
常用类型
除了我们上面说的 number 类型,还有这几个 常用 类型:string boolean undefined null。
当然了复杂类型也是有的,
var list:string[]=[]
表示的是变量 list 是一个数组,这个数组里面每个元素都是 string。
对象
function f1(a: { name: string; age: number}) {}
上面的代码,表示参数 a 是一个 对象
,这个对象上有 name 和 age 两个属性,并且这两个属性的类型分别是 string 和 number,那么当我们调用这个函数的时候,就要出符合条件的参数,不符合的话,ts 就提示代码写的有问题了。
我们也可以用 interface
来声明一个对象结构,
interface af {
name: string
age: number
}
function f1(a:af) {}
和 Java 的 interface 有点像但不太一样,我们把它理解成用来声明一个 结构
,这个结构长成这个样子:有属性 xxx,对应的值是 string 类型,有属性 yyy,对应的值的类型是 number……
有个注意的点是,当我们传入的参数多了一些的属性的话,ts 也会提示报错:
那么要解决这种情况,一种方式是改造我们的 interface 成这样子:
interface af {
name: string
age: number
[attr:string]:any
}
多出来的 [attr:string]:any
意思是说我这个 af 上,还可能有一些其他的属性,对应的属性值的类型是 any。
同样的,当我们往 a 上面赋值一些新的属性的时候,也会提示,
我们也要加[attr:string]:any
。
另外一种方法参看文章后面的类型断言。
函数类型
现在,我们这里有个参数 callback,它是一个函数类型,那怎么声明呢:
其中 void 表示这个函数没有返回值。那通常,我们的回调函数会需要一些参数来接受数据:
当然我们也可以把这个 callback 的类型给提取出来,用 interface 声明一个函数类型(是的,你没看错……就是刚才用来声明对象的 interface,目前你知道了它有两个作用了)
interface ccc{(data:string):void
}
function getInfo(id:number,callback:ccc){}
注意写法有点稍微不一样,一个是=>void
一个是:void
字面量类型
上面,a3 和 a4 就只能是固定的字面量 "name"
或者 1
了。
还有个 any 类型,顾名思义,表示任意类型,是其他类型的子类型。
你看,本来 f2 是要传一个 number 进来的,我们传了一个 any 类型进去也不报错,一般是,当我们不指明变量(常量、参数、返回值)类型,ts 又推断不出来的时候,ts 会推断成 any 类型。(这个需要到 tsconfig.json 里面配置)
类型之间运算
用 |
表示或的意思:
比如这里,我们告诉编译器,u1 这个变量可能是 1 也可能是 2,也可能是 3。
再比如:
var u2:"aaaa"|1|{a:string}
可能是三种完全不同的类型。
用 &
表示合并两个类型:
这样,u1 就有 a 和 b 加一块的属性了。
声明一个类型
使用 type
来声明一个类型,比如说,上面的一长串 "aaaa"|1|{a:string}
我们再很多地方都要用到,我们可以提取出来,起个名字供大家调用:
type uu="aaaa"|1|{a:string}
var u3:uu
...
var u4:uu
interface a {aaa: string}
interface fc {(data: string): void
}
type uu2 = a & fc
类型断言
啥是类型断言呢,顾名思义,就是对类型的判断。比如我们上面举的一个例子:当传进来的参数不符合要求时,
使用 as 语句,告诉编译器 / 编辑器,“你就把我传进来的参数当成符合 af 接口的数据吧”,相当于我人肉判断了,我传的参数类型我知道符合条件。
再比如:声明变量的时候:
非空断言
有一种情况,如下,当我们在 tsconfig.json 里面开启了严格的 null 检查的时候,
这时候,当然我们 使用 as string 就可以搞定,其实还有个小技巧,使用 !
告诉 ts 这个变量不是 null 也不是 undefined
类型保护
说白了就是当我们使用一个变量的时候,当访问到可能不存在的属性或方法的时候,强制要求做类型判断:
使用 typeof
比如这个例子:
参数 a 可能是 number 或者 string,默认情况下,只能调用 number 和 string 都有的方法。当调用 number 独有的方法比如说 toFixed 的时候就报错了。这时候你就应该判断一下,如果是 number 类型的再调用 toFixed
上面的例子,你会发现,ts 还是挺智能的,自动推断出 else 的情况就是 string 类型。
使用 instanceof
instanceof 差不多,主要用来判断是不是一个类的对象。
使用 in
你可能会机智的想到了,那假如类型是 interface 呢,js 里面可没有这东西
ts 也做了非常聪明的推断,就不详细说了。
泛型
有时候,我们的几个类型非常相似,只有一两个参数不一样,比如常在 CMS 开发中定义接口返回值类型的情况,如下面的 UserResponse 和 RoleResponse
interface User{
name: string
age:number
}
interface Role{
name: string
id:string
}
interface UserResponse{
ret: number
message:string
data:User
}
interface RoleResponse{
ret: number
message:string
data:Role
}
这时候我们就在想能不能把公共的部分提前出来作为一个通用的类型,然后这个通用的类型接收不同的参数并生成新的类型?当然是可以的:
interface CommonResponse<T>{
ret: number
message: string
data: T
}
type UserResponse = CommonResponse<User>
type RoleResponse=CommonResponse<Role>
你会发现泛型有点类似于函数参数。
泛型默认值
和函数参数一样,我们也可以给泛型设置个默认值,当不传的时候就使用默认值。
interface T1<T = any>{
aaa: string
t:T
}
多个泛型
也支持多个泛型,
interface T1<T ,K> {
aaa: string
t: T
k:K
}
泛型约束 extends
有时候,我们想要约束一下传进来的泛型的类型:
使用 extends 来约束
泛型除了可以用在 interface 上,还可以用在 type、class、function 上:
type t1<T> = {aaa: T}
type t2<T> = string | T
class C<T> {
aaa: T
constructor() {}
}
function get<T>(a:T) :T{return a}
var g = get<string>("")
这里说一个特别常用的例子:Promise,
不加泛型的时候,ts 不知道 await get()的返回值是什么类型,加了泛型之后就知道了,并且能智能提示了:
tsconfig.json
本质上,我们写的 ts 代码最终会编译 js 代码,比如删除掉 ts 代码里面的类型接口等。那么这个编译行为有许多参数可以控制,最常用的方法是在项目根目录创建一个 tsconfig.json 的文件,ts 编译代码的时候会根据里面的配置进行编译。
通过命令行执行 tsc
将 ts 代码编译成 js 代码。tsc -w
监听文件变化自动编译代码。
tsc -init
可以生成 tsconfig.json
文件。