TypeScript极速版

6,143 阅读11分钟

完了,现在的企业,都要求前端开发使用typescript了,项目更好维护了,我们来错地方了。
我倒是觉得用typescript不错。
前端都成牛马了,没油水可榨了。
老子从来就没想要过牛马的钱。
不压榨前端牛马你怎么挣钱?
谁有钱挣谁的。
当过前端吗?
没有。
来,我告诉告诉你,当前端,你得巧立名目,拉拢豪绅,怎么复杂怎么写,怎么难维护怎么写,让老板带头掏钱出来扩招前端,他们招了,才能让前端牛马出钱去培训,得钱之后,老板的钱如数奉还,牛马的钱三七分成。 怎么才七成啊?
七成是人家的,能得三成还得看他的脸色。
谁的脸色?
他!
他?我大老远的来一趟,就是为了看他的脸色?
对。 我好不容易考上了个大学,入行当了前端,还要拉拢豪绅?
对。
还要巧立名目?
对。
还要看他的脸色?
对。
那我不成了跪着要饭的吗?
那你要这样说,当前端还真就是跪着要饭的。就这,多少人想跪还没这门子呢!

我学技术,就为了三件事,效率!效率!还是TMD效率! 1.jpg

TypeScript是什么

官方文档上说,TypeScript是JavaScript的超集。简单的理解,你可以认为它是JavaScript Pro,它扩展了JavaScript的语法。

TypeScript解决了什么问题

既然是对JavaScript的扩展,那么必然是因为JavaScript本身的一些限制导致需要补足。
首先就是长久以来对于JavaScript是一个弱类型语言的诟病,所以针对这点,TypeScript则是引入了静态类型检查,允许开发者在编写代码时指定类型,并在编译时捕获类型错误,从而提高了代码的质量和可靠性。
其次TypeScript这样的静态类型也使得编辑器和IDE能够提供更强大的功能,比如自动补全、快速导航等等。 当然TypeScript还提供了诸如面向对象编程的支持,文档和类型的定义等其他的功能,这里就不一一概述了。总而言之,对于企业而言,需要前端开发掌握TypeScript这样的技能大体都是因为可以提高生产效率,使得负责代码结构管理起来更加容易,从而节省开发资源~

快速掌握才是根本

即便到了4202年,对于TypeScript是否可以提高效率的问题依旧会有争执,但是对于我们普通的前端开发者来说,掌握TypeScript既是招聘市场的要求,也是可以变相提高岗位薪资的手段,所以本着会总比不会好的原则,快速掌握TypeScript才是王道。 2.jpg

掌握核心知识点就能解决80%的问题

对于前端的任何一个技能,我个人的理解都是先不要太深入,很多时候企业不是需要一个某一项技能的专家,而只是一个熟练的使用者而已。我们先去掌握一项技能的核心的知识点,当这些知识点不能满足我们的需求的时候,再去考虑深入了解一下,毕竟前端的技能方向又多又杂且说不好某些技术会在未来被新的技术取代,而我们个人的精力是有限的。下面我就简单梳理一下TypeScript里我认为比较核心的知识点,帮助大家快速掌握~

1. 类型推断

3.jpg 首先我们写了一个 str 变量,并且在下一行把 str 修改成了10,我们会看到在 Typescript 环境下出现了报错,告诉我们不能把一个数值分配给一个字符串类型。
这是因为 Typescript 会根据你给变量存放的初始值来进行变量类型推断,也就是说我们在一开始给 str 的值是一个字符串,那么这个 str 变量以后就只能存放字符串值。

2. 类型注解

我们上面演示的这种操作方式叫做类型推断,是 Typescript 根据我们已书写的代码进行推断的方式,但是这种方式并不直观,在我们实际开发中,更推荐大家使用类型注解的方式。

let str: string = 'hello'

使用方式就是通过在变量后加冒号的方式来指定变量的类型,这样我们就明确的注明了这个 str 变量是一个字符串。当然你也可以初始的时候不赋值,只做一个预声明,声明一个变量,当你后面要使用到这个变量的时候,如果类型不匹配,Typescript 也会给我们一个报错。 4.jpg

3. 类型断言

除了类型推断和类型注解,TypeScript 还有一种类型断言的方式。我们看下面的示例: 5.jpg 我们需要找到 strArray 中找出等于 'b' 的这一项,并且和 'd' 字符串合并,很明显 b 字符串在 strArray 数组中是存在的,但是我们在使用 concat 的时候报错 result 可能是 undefined,而显然这不是我们希望看到的,那么在这里我们就可以使用类型断言的方式了。

let strArray = ['a','b','c']
const result = strArray.find(i => i === 'b') as string
result.concat('d')

通过 as 告诉TypeScript,我们断言 result 一定是一个字符串类型。当然我们还有一种 AnyScript 的高级写法:

let strArray = ['a','b','c']
const result = strArray.find(i => i === 'b') as any
result.concat('d')

6.jpg

4. 基础类型和联合类型

下面我们演示一下TS中可以使用的基础类型

let t1: string = 'abc'
let t2: number = 10
let t3: boolean = true
let t4: null = null
let t5: undefined = undefined

诶,当我们看到 null 和 undefined 的时候,可能会疑惑,这种类型都是使用频率极低的,那为什么 TypeScript 还有这种类型呢?
那其实是因为 TypeScript 其实还支持另外一种操作,就是联合类型,比如说我们定义了一个变量,希望他最终可能会被分配成字符串,也有可能被分配为空,那么我们就可以用联合类型来表述。

let t6: string | null = null

再比如说,我们希望一个 mode 变量可能是固定的几个值中的一个,我们就可以这么写:

let mode: 'scaleToFill' | 'aspectFit' | 'aspectFill' = 'aspectFill'

那么看到这里大家可能就会很熟悉了,我们 input 标签的 type 属性不就可以使用联合类型来约束嘛。

5. 数组,元组,枚举

下面我们再来介绍一下一些复杂的类型以及一些新的类型,先拿数组来举例,当我们需要一个数组的时候,TypeScript 中是有多种写法的:

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

你可以选择一个你比较喜欢的写法即可。那么除了数组之外呢,TS中还提供了一些类似于数组的结构,比如说元组,元组也可以存储多个数据,但是他限制了你存储数据的个数以及每个数据的类型,听着好像有点晦涩,直接上代码。
Talk is cheap.Show me the code.

let arr: [number, string, number] = [1,'2',3]

这样就构成了我们的一个元组的结构。当然了,这里面还有个小技巧,假如说我们希望某一个值是可选的,我们可以按照下面的写法去写:

let arr: [number, string, number?] = [1,'2',3]

我们可以采用问号的一个方式来写,这样假如你的 arr 数组只有 [1,'2'] 他也是不会报错的。
除了元组类型之外呢,TS 还提供了枚举类型,而枚举则是需要使用 enum 这个关键字来声明。

enum SexStatusEnum {
  /** 女性 */
  female,
  /** 男性 */
  male,
}

这个时候我们可以使用两种方式来访问

console.log(SexStatusEnum.female)
console.log(SexStatusEnum[0])

这里我们需要知道的是,当枚举类型我们声明好之后,TS 是会自动做值的分配的,默认是从0开始,当然我们也可以手动的去修改值:

enum SexStatusEnum {
  /** 女性 */
  female = 'female',
  /** 男性 */
  male = 'male',
}

除此之外,我们还要介绍一下 void 类型,代表空的意思,在我们使用的时候,在严格模式下,void 只能被分配给 undefined。
我们在其实开发的过程中很少会给变量赋这个值,通常是在函数中使用,比如一个函数没有返回值的时候。

6. 函数

我们上面提到 void 一般是在函数中使用,下面就演示一下: 7.jpg 我们可以看到有一个报错,因为我们上面提到了 void 代表的是空的意思,但是我们的函数明显是有返回值的,所以这里的void应该改成number。
在函数中很多时候某些入参是可选的,我们可以使用上文中提到的方法,通过 ? 的方式:

function MyFunction (a: number, b?: number): number {
    return 100
}

这里我们需要注意的是,你的可选参数必须在必选参数的后面。
还有一些场景呢,是需要给我们的入参赋一个默认值,我们也可以按下操作:

function MyFunction (a: number = 10, b?: number): number {
    return 100
}

我们再补充一个小技巧,当我们还有其他的参数需要传递的时候,是不是都需要这样按个指定呢,其实是不需要的,还真把前端当牛马了哇。 8.jpg

function MyFunction (a: number = 10, b?: number, ...rest: number[]): number {
    return 100
}
MyFunction(1,2,3,4,5,6,7,8,9)

我们可以像上面一样,使用一个 rest 进行解构即可。

7. 接口

接口通常用来对一个对象进行定义~ 9.jpg

interface MyObject {
    name: string
    age: number
    height: number
}
const obj: MyObject = {
    name: '刘亦菲',
    age: 28,
    height: 170
}

我们看到这样一个我的对象就定义好了,当然需要注意的一点是,这里如果我定义 obj.name 是刘亦菲可能没有问题,但是你定义 obj.name 是刘亦菲可能就是个bug。

8. 类型别名

比如说我们定义一个变量a,我认为这个a可能会有两种类型,可能是number,也可能是string,那么我们这里就可以使用一个类型别名 type 来定义。

type MyType = string | number
let a: string | number = 10
let a1: MyType = 10

9. 泛型

那么在 TS 中还有个比较常用的概念,就是泛型。

function myFun (a: number, b: number): number[] {
    return [a, b]
}

比如说我们现在定义了一个方法,接受两个number参数,最后返回了一个number数组,但是可能后面我希望通过这个函数处理一串字符串,一串布尔值等等,这个时候我们的类型约束就不能满足需求了,我们需要的是一个比较通用的函数,这里就可以采用一个泛型的概念。

function myFun<T> (a: T, b: T): T[] {
    return [a, b]
}

我们看到在myFun后面声明了一个泛型变量,当然可能大家看到使用 T 会比较多,而在大家实际使用中可以取任意的变量名。那么我们怎么使用呢?

function myFun<T> (a: T, b: T): T[] {
    return [a, b]
}
myFun<number>(1,2)
myFun<string>('1','2')

当我们给 myFun 传 number 的时候,那么这些 T 的位置就都是number,当传 string 的时候,这些 T 的位置就是string了,当我们使用了泛型来约束的时候,这个 myFun 就变成了一个通用的函数,可以接受一串任意类型的数据了。

function myFun<T> (a: T, b: T): T[] {
    return [a, b]
}
myFun('1','2')

需要注意的是,我们在第一个知识点讲过,TS 还支持类型推断,当我们给 myFun 传递一个 string 类型的数据的时候,TS 就会推断你这个 T 不就是 string 类型嘛,他会按照你第一次推断的那个值来进行 T 的应用。

结语

当然关于 TS 的用法还远不止上面的9个知识点,比如还有交叉类型,Pick,Omit,Exclude等等。但是按照我们上述的观点,快速掌握一项技能只需要掌握其核心知识点即可,剩余的知识点可以在大家实际开发中需要用到的时候再补充。
相信大家掌握了这个技巧之后一定可以快速的学会其他的技能了,那么下面我们就来学习一道算法题: 10.jpg