跟着我十分钟学会 TypeScript
接下来在这一节,我们将利用一整节的时间去聊一下 Typescript,希望你在学完这一节之后,能对 TypeScript 有一个全面的认识
安装 Typescript
npm install -g typescript
提出问题
TypeScript 是用来做什么的 ❔
我们在学习一门新课程时,都会有这种疑惑 😖 那就是这个东西我们学来是干什么用的
现在,我就用一个最简单的例子来回答你
if ("" == 0) {
// 他们相等!但是为什么呢??
}
像上面是一行最简单的 javaScript 判断代码,但是令我们疑惑的是,这两个值为什么会相等
这是因为 0 与 " " 转换成布尔型都是 false
的,也正是由于 JavaScript 的等于运算符会试图强制值相等,才出现这种匪夷所思的事情
下面,我们再换成一个简单的 TypeScript 小例子
在下面的代码中,我们定义了一个字符串类型 name,当我们把 String
类型的变量赋值给 Number
时,就会报错
let name:string = '《Vue3从入门到就业》'
name = 888 //类型报错
由此不难看出,TypeScript 可以在 JavaScript 的基础上,对变量的数据类型加以限制
那么下面就让我们继续探讨 TypeScript , 具体看看它带来了什么特性和语法
TypeScript 入门
1. any 类型
当你不确定某个变量是什么类型时,你可以使用 any
作为这个变量的类型
你可以用 any
标记任何属性,可以修改任何数据,访问任何方法也不会报错
也就是说,在 TypeScript 中,当你把变量的类型标记为 any
后,这个变量的使用就和 JavaScript 没啥区别了,错误只会在浏览器里运行的时候才会提示
let name : any = 4
name = '《Vue3从入门到就业》'
name = true
// 允许调用任何方法:
notSure.getName()
2. enum 枚举
使用 enum
去定义枚举类型,这样可以把类型限制在指定的场景之内
下面我们来尝试做数字枚举,然后这里面的值,枚举成员会被赋值为从 0 开始递增的数字
enum Direction { Up, Down, Left,Right }
console.log(Direction.Up) // 0
还有一个神奇的点是这个枚举还做了反向映射
console.log(Direction[0]) // Up
那我们再来试试字符串的枚举
// 字符串枚举
enum Direction {
Up = 'UP',
Down = 'DOWN',
Left = 'LEFT',
Right = 'RIGHT',
}
const value = 'UP'
console.log( value === Direction.Up ) // true
3. | 实现类型联合
然后我们可以使用 | 实现类型联合,通过组合的方式组合出新的类型
下面的代码中我们定义 name 变量的类型为字符串或者数字,赋值为这两个类型都不会报错
let name : string|number = '《Vue3从入门到就业》'
name = 8888
name = true // 报错
还可以用来限制变量只能赋值为几个字符串的一个,score 的取值只能是代码中三个值之一
type Fruits = '香蕉' | '苹果' | '西瓜'
let Fruits1 :Fruits = '香蕉'
let Fruits2 :Fruits = '汉堡包' // 报错
4. interface 接口
通过 interface 接口可以定义对象的类型限制
比如下面我们定义一个数据 Person
(人)
interface Person {
name: string;
age: number;
}
接着定义一个变量 Chinese
(中国人),它的类型是 Person
这样,我们就约束了 Chinese
的形状必须和接口 Person
一致
let Chinese: Person ={
name: '黄勇超',
age: 22
}
当有时候我们希望不要完全匹配一个形状,那么可以用可选属性:
interface Person {
name: string;
age?: number;
}
let Chinese: Person = {
name: '黄勇超'
}
有时候我们希望对象中的一些字段只能在创建的时候被赋值,那么可以用 readonly
定义只读属性
interface Person {
name: string;
age: number;
readonly id:string
}
let Chinese: Person = {
name: '黄勇超',
age: 22
id:"88888"
}
Chinese.id = '99999' // 报错
5. 函数的类型限制
函数的定义,参数和返回值本质上也是变量的概念,都可以进行类型的定义
基础语法
function 函数名(参数:参数类型):返回值类型{}
比如下面的代码中我们定义了参数 x 和 y 是数字,返回值也是数字
function add(x: number, y: number): number {
return x + y
}
同样的,我们也可以设置可选参数
function add(x: number, y: number, z?: number): number {
if (typeof z === 'number') {
return x + y + z
} else {
return x + y
}
}
6. type 类型别名
类型别名,就是给类型起一个别名,让它可以更方便的被重用
let sum: (x: number, y: number) => number
const result = sum(1,2)
type PlusType = (x: number, y: number) => number
let sum2: PlusType
支持联合类型
type StrOrNumber = string | number
let result2: StrOrNumber = '123'
result2 = 123
字符串字面量
type Directions = 'Up' | 'Down' | 'Left' | 'Right'
let toWhere: Directions = 'Up'
TypeScript 轻进阶
讲完上面的内容,你就已经能使用 TypeScript 实现很多项目的开发,把所有变量和函数出现的地方都定义好类型,就可以在编译阶段提前规避出很多报错,接下来我们再往下进行轻进阶的课程
1. 类型断言
as 关键字,告诉 TypeScript 编译器,你没法判断我的代码,但是我本人很清楚,这里我就把它看作是一个 string
,你可以给他用 string
的方法
function getLength( input: string | number ): number {
const str = input as string
if (str.length) {
return str.length
} else {
const number = input as number
return number.toString().length
}
}
2. Generics 泛型
泛型是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性
如下面的代码
function getTitle(title) {
return title
}
const result = getTitle('《Vue3从入门到就业》')
这时候我们发现了一个问题,我们传入了字符串,但是返回了 any
;这时候我们使用泛型
我们在函数名之后使用 <> 定一个泛型 T,你可以理解这个 T 的意思就是给函数参数定义了一个类型变量,会在后面使用,相当于【type T = title 的类型】,返回值使用 T 这个类型就完成了这个需求
function getTitle<T>(title: T): T {
return title
}
const result = getTitle('《Vue3从入门到就业》')
console.log(result) // '《Vue3从入门到就业》'
泛型也可以传入多个值
function getTitle<T, U>(title: [T, U]): [U, T] {
return [title[1], title[0]]
}
const result = getTitle(['《Vue3从入门到就业》', '黄勇超'])
有了泛型之后,我们就有了把函数参数定义成类型的功能,我们就可以实现类似高阶函数的类型函数
下面的代码中我们使用 keyof
语法获得已知类型 Person 的属性列表,相当于 "name"| "price" :
interface Person {
name:string,
age:number
}
type Chinese = keyof Person // 只能是 name 和 age 选一个
let k1:Chinese = 'name'
let k2:Chinese = 'age' // 改成 age
keyof
可以帮助我们拆解已有类型;下一步我们需要使用 extends
来实现类型系统中的条件判断
我们定义类型函数 name,接受泛型参数 T 后,通过判断 T 是不是布尔值来返回不同的类型字符串,我们就可以通过 name 传入不同的参数去返回不同的类型
🔔:
T extends U ? X : Y
类型三元表达式
type name <T> = T extends boolean ? " Vue 2 " : " Vue 3 "
type name1 = name<boolean> // type name1= ' Vue 2 '
type name2 = name<string> // type name2= ' Vue 3 '
extends
相当于 TypeScript 的条件语句,然后 in
关键字可以理解为 TypeScript 的遍历
下面的代码中我们通过 k in name 语法,相当于遍历了 name 所有的类型作为 nameObj 的属性
type name = ' Vue 3 '|' Vue 2 '
type nameObj = {
[k in name]:number // 遍历name类型作为key
}
上面的代码等于下面的定义
type nameObj = {
Vue 3 : number;
Vue 2: number;
}
接下来我们再来讲解最后一个关键字 infer
让我们拥有了给函数的参数定义类型变量的能力,infer
则是可以在 extends
之后的变量设置类型变量,更加细致地控制类型
下面的代码中我们定义了 ReturnType 类型函数,目的是返回传入函数的返回值类型
infer P 的意思就是泛型 T 是函数类型,并且这个函数类型的返回类型是 P
type Foo = () => CourseObj
如果 T 是一个函数,并且函数返回类型是 P 就返回 P
type ReturnType1<T> = T extends ()=>infer P ?P:never
type Foo1 = ReturnType1<Foo>
作者:黄勇超
岗位:技术部门主管 | 前端开发工程师
团队:奇霖开发团队
转载自:https://juejin.cn/post/7141960553094152205