今年年初的时候入职了新的公司,技术栈使用的是 Vue + Typescript,先不说 Vue,TS 之前只是看了一些文章和官方文档,只是知道能在变量后面加个类型,就可以限制变量。后来入职后,不知不觉也写了大半年 TS,对于那些变量或函数要写,为了写了返回类型,VSCode 提示返回值还是 any 类型,泛型的具体应用,接口定义怎么写之类的问题,有了一点理解。

TS 是写给谁看/用的?

首先,TS 是定义者给使用者写的。为了让使用者更方便(VSCode 提示)以及更安全(约束)的使用他提供的方法或者类。
使用 TS,是有两个方式的,定义和使用。

VSCode 提示

例如:定义者指定了一个方法:

1
2
3
export function foo(name: string): number {
return name.length
}

那么作为使用者, 你会很清晰的通过 VSCode 的提示了解到该函数的参数和返回值信息:
Image text

而不需要去看源码,一些复杂的方法,如果没有良好的注释,即使看源码也不一定能很快的判断出来参数和返回值类型。

为了提供更完美的 VSCode 提示信息,还可以给方法加一个注释:

1
2
3
4
5
6
/** foo function
* @description count string size
*/
export function foo(name: string): number {
return name.length
}

这时候使用者看到的是:
Image text

所以,当要提供一个方法或者类给别人用的时候,就需要把类型约束好,这样才能让使用者更好的使用。这里的提供给别人使用,往大了说就是提供一个第三方类库或者框架给别人用,如:axios lodash 等,往小了说可能就是提取一个公用的方法到你的 utils 文件夹下。

类型推断

其实也不是所有的变量或者返回值都需要手动去设置类型,通过类型推断,可以少些很多代码。

我们看下面的例子:

1
2
3
4
export function splitString(str: string) {
const separator = ','
return str.split(separator)
}

这里的 separator 就可以不用写成 separator:string,TS会进行类型推断。
进一步,返回类型我们也可以不用定义,TS 会根据 split 方法的返回类型来推断 splitString 的返回类型。

Image text

类型推论只适用于一些简单的类型,复杂的情况还是需要手动定义。可以通过 VSCode 的提示检测是否正确推断了类型。
说的极端一点,TS 就是为了让使用者爽,有更好的提示和约束,让你知道你是否有正确安全的使用提供的方法。而不是为了增加工作量和心智负担。

interface 接口

接口的作用就是为这些类型命名和为你的代码或者第三方代码定义规则,简单来说接口就是用于封装一系列的需求限制条件

class 类

描述了所创建的对象共同的属性和方法。

什么时候用泛型

要知道这个问题之前,首先要知道什么是泛型,泛型解决了什么问题。可以先看看文档。
在了解了泛型是让一个组件及其参数支持多种类型之后。如果还不知道什么时候用泛型,那就是还不需要用。等遇到了痛点,自然就会想到泛型了。
比如定义了一个方法:

1
2
3
function foo (arg:number):number {
return arg
}

当需要让这个方法支持 string 类型的时候,不使用泛型的话,你可能这么写:

1
2
3
function foo(arg: number | string): number | string {
return arg
}

这里有个问题,会出现传入 number,返回 string 这样的情况,不够严谨。
这个时候就会想到泛型了。

1
2
3
function foo(arg: T): T {
return arg
}

当然,泛型的玩法不都是那么简单的,想要玩出更高阶的泛型写法,可以多看看第三方库写的类型定义文件,看看别人是怎么写各种泛型的。

类型定义在哪?

这个问题跟上面的问题是一样的,当你不知道这玩意什么时候用,那你应该是还用不到这个玩意儿。
简单的不重用的就直接写,如上面的示例方法。
需要重用的一般来说就在方法实现的文件夹自定义一个类型,并 export 出去,方便其他使用者使用。

1
2
3
4
5
export type fooItem = string | number | null

function foo(arg: fooItem): void {
console.log(arg)
}

也可以用一个文件夹,专门放各种公用数据类型。比如在定义前后端接口数据的时候,就可以这么干:

1
2
3
4
5
6
7
8
9
10
11
// ./src/model/user.ts
export interface userReq {
username: string
password: string
}

export interface userRes {
nickname: string
avatar?: string
age: number
}

总结

本文没有讲TS的技巧,没有讲TS的优点,就是我基于个人使用 TS 的经验进行简单的解答和讲解,讲的比较凌乱。

其实 TS 没有想象的那么复杂,TS 的初衷是在帮助开发者,服务开发者,要享受 TS 带来的便捷和快感。结尾用一句几乎每个用过 TS 的人都会说的话:

用了 TS 就回不去 JS