接下来在这一节,我们将利用一整节的时间去聊一下 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 , 具体看看它带来了什么特性和语法
当你不确定某个变量是什么类型时,你可以使用 any
作为这个变量的类型
你可以用 any
标记任何属性,可以修改任何数据,访问任何方法也不会报错
也就是说,在 TypeScript 中,当你把变量的类型标记为 any
后,这个变量的使用就和 JavaScript 没啥区别了,错误只会在浏览器里运行的时候才会提示
let name : any = 4 name = '《Vue3从入门到就业》' name = true // 允许调用任何方法: notSure.getName()
使用 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
然后我们可以使用 | 实现类型联合,通过组合的方式组合出新的类型
下面的代码中我们定义 name 变量的类型为字符串或者数字,赋值为这两个类型都不会报错
let name : string|number = '《Vue3从入门到就业》' name = 8888 name = true // 报错
还可以用来限制变量只能赋值为几个字符串的一个,score 的取值只能是代码中三个值之一
type Fruits = '香蕉' | '苹果' | '西瓜' let Fruits1 :Fruits = '香蕉' let Fruits2 :Fruits = '汉堡包' // 报错
通过 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' // 报错
函数的定义,参数和返回值本质上也是变量的概念,都可以进行类型的定义
基础语法
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 } }
类型别名,就是给类型起一个别名,让它可以更方便的被重用
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 实现很多项目的开发,把所有变量和函数出现的地方都定义好类型,就可以在编译阶段提前规避出很多报错,接下来我们再往下进行轻进阶的课程
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 } }
泛型是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性
如下面的代码
function getTitle(title) { return title } const result = getTitle('《Vue3从入门到就业》')
这时候我们发现了一个问题,我们传入了字符串,但是返回了 any
;这时候我们使用泛型
我们在函数名之后使用 <> 定一个泛型 T,你可以理解这个 T 的意思就是给函数参数定义了一个类型变量,会在后面使用,相当于【type T = title 的类型】,返回值使用 T 这个类型就完成了这个需求
function getTitle(title: T): T { return title } const result = getTitle('《Vue3从入门到就业》') console.log(result) // '《Vue3从入门到就业》'
泛型也可以传入多个值
function getTitle(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 extends boolean ? " Vue 2 " : " Vue 3 " type name1 = name// type name1= ' Vue 2 ' type name2 = name// 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 extends ()=>infer P ?P:never type Foo1 = ReturnType1
有话要说...