TypeScript
这篇文章主要总结了TypeScript
一.TypeScript 概述
是什么?:TS是微软开发的编程语言,他是JS的超集,可以在任何运行JS的地方运行
官方文档,中文文档
TypeScript = Type + JavaScript(在 JS 基础之上,为 JS 添加了类型支持/类型检测)
1.优势:
背景:JS是弱类型语言,而在代码中很多错误都是类型错误,
他不像其他强类型语言一样有类型检测,比如JAVA,因此出现了TS
1.发现错误的时机更早,即TS在编译时,即代码执行前就会出现类型检测
2.代码提示,JS代码没有代码提示,需要插件才能支持代码提示
3.支持最新的ECMAScript语法
4.Vue3源码使用TS重写,React 也与 TS 完美配合
2.安装并编译TS
1.安装命令:npm i -g typescript 或者 yarn global add typescript
2.验证是否安装成功:tsc –v(查看 TypeScript 的版本)
3.创建 hello.ts 文件(注意:TS 文件的后缀名为 .ts)。
4.将 TS 编译为 JS:在终端中输入命令,tsc hello.ts(此时,在同级目录中会出现一个同名的 JS 文件)。
5.执行 JS 代码:在终端中输入命令,node hello.js。
说明:所有合法的 JS 代码都是 TS 代码,有 JS 基础只需要学习 TS 的类型即可。
注意:由 TS 编译生成的是 JS 文件,生成的代码中就没有类型相关的信息了。
3.创建Vue TS项目
在基于 Vite 的项目中可以直接验证 TS 代码结果,因为已经配置好了 TS 环境。
# npm 6.x
npm create vite@latest my-vue-ts-app --template vue-ts
# npm 7+, extra double-dash is needed:
npm create vite@latest my-vue-ts-app -- --template vue-ts
# yarn
yarn create vite my-vue-ts-app --template vue-ts
# pnpm
pnpm create vite my-vue-ts-app --template vue-ts
二.TS基础
1.原始类型
语法:const 变量名:数据类型 = 与数据类型匹配的值
与数据类型匹配的值的意思时,比如数据类型写的数字,那么你的值必须写数字
const num: number = 18
console.log(num.toFixed(2))
const str: string = '龚贤龙'
const b: boolean = true
const u: undefined = undefined
const n: null = null
//const big:bigint = 888888888888888n
//console.log(big)
const sym: symbol = Symbol()
2.数组类型
语法1:const 变量名: Array<number> = [ 1, 2, 3 ]
语法2:const 变量名: number[] = [ 1, 2, 3, 4 ]
这两句代码表示该变量现在为数字组成的数组
const list: Array<number> = [ 1, 2, 3 ]
const list1: number[] = [ 1, 2, 3, 4 ]
3.联合类型
语法:const 变量名: (number | string)[] = [ 1, 2, '3', '4' ]
这句代码表示该变量限制类型为数字和字符串组成的数组
const arr: (number | string)[] = [ 1, 2, '3', '4' ]
const arr1: Array<number | string> = [ 1, 2, '3', '4' ]
4.类型别名
语法:type 类型别名 = 数据类型
let 变量名 :类型别名 = 数据
type uname = String
let zname: uname = '龚贤龙'
type arr2 = (number | string)[]
const arr3: arr2 = [ 1, 2, 3, 'gh', 'sf' ]
console.log(arr3)
5.函数类型
函数如果不指定返回值,默认void类型主要是分别指定参数与返回值的类型
方式1
//普通函数声明
function sum(num1: number, num2: number): number {
return num1 + num2
}
sum(1, 3)
//函数表达式
const sum1 = (num1: number, num2: number): number => {
return num1 + num2
}
sum1(1, 4)
方式2
//同时指定参数与返回值,只适用于函数表达式
type TFn = (num1: number, num2: number) => number
const sum3: TFn = (num1, num2) => {
return num1 + num2
}
sum3(5, 8)
6.void类型
作用:当一个函数没有给他的返回值指定类型时,它默认是void类型
function ok(): void {}
7. ? 可选参数
注意1:可选参数必须放在必选参数后面
function slice(start?: number, end?: number): any[] {
console.log(start, end)
return []
}
slice()
slice(1)
slice(1, 2)
注意2:数组默认参数 不能和可选参数一起使用
function slice1(start: number = 10, end?: number): any[] {
console.log(start, end)
return []
}
slice1()
slice1(1)
slice1(1, 2)
8.对象类型指明参数类型
const obj: { name: string; age: number } = {
name: '龚贤龙',
age: 29
}
或者
const o = {
name: '龚贤龙',
age: 29
}
const obj: { name: string; age: number } = o
9.interface接口与extends继承
interface Point2D {
x: number
y: number
}
// 使用 `extends`(继承)关键字实现了接口 Point3D 继承 Point2D
// 继承后,Point3D 就有了 Point2D 的所有属性和方法(此时,Point3D 同时有 x、y、z 三个属性)
interface Point3D extends Point2D {
z: number
}
10.interface与type
相同点:
1.都可以描述对象和函数
2.都可以进行类型扩展,但语法不一样
//interface用的extends
//type用的&符号,形成的叫交叉类型
不同点:
1.type可以描述任意类型,interface做不到
2.相同的interface会合并,相同的type会报错
总结
一般用于interface描述对象,用type来描述类型之间的关系
11.字面量类型
字面量类型往往配合联合类型一起使用
使用场景:用来表示一组明确的可选值列表,比如在贪吃蛇游戏中,
游戏方向的值只能是上、下、左、右中的一个。
type Direction = 'up' | 'down' | 'left' | 'right'
function changeDirection(direction: Direction) {
console.log(direction)
}
changeDirection('up') // 调用函数时,会有类型提示
解释:参数direction的值只能是 up/down/left/right 中的任意一个。
优势:相比于 string 类型,使用字面量类型更加精确、严谨。
12.类型断言 as
往往把一个宽泛的类型断言为一个更加具体的类型,为使用这个更加具体的属性和方法
语法1:const oLink = document.getElementById('link') as HTMLAnchorElement
语法2:const oLink = <HTMLAnchorElement>document.getElementById('link')
第二种语法了解即可
13.特殊类型 any/unknown/never
1.unknown是更加安全的any类型(有一些可能导致程序的报错的操作会提示出来)
2.任何类型都可以给any,any也可以给任何类型
3.任何类型都可以给unknown,unknown只能给unknown和any
4.unknown一般配合类型收窄一起使用(typeof 可以类型收窄,as断言可以类型收窄)
5.never不可能实现的类型
type Test = number & string
// 也可以当做函数的返回值,表示不会执行到头
function test(): never {
throw new Error('Error')
}
三.TS泛型
1.泛型别名
定义类型别名后,加上 <类型参数> 就是泛型别名语法,
使用的时候传入具体的类型即可,然后类型别名内就可以使用这个类型参数。
// 对后台返回的数据进行类型定义
type User = {
name: string;
age: number;
}
type Goods = {
id: number;
goodsName: string;
}
type Data<T> = {
msg: string;
code: number;
data: T
}
// 使用类型
type UserData = Data<User> //把user作为参数传递给T
type GoodsData = Data<Goods> //把goods作为参数传递给T
2.泛型接口
接口也可以配合泛型来使用,以增加其灵活性,增强其复用性
interface User<T> {
name: T
age: number
}
const user: User<string> = {
name: 'ifer',
age: 18,
}
//数组泛型接口的实现
// 这其实也是通过泛型接口的形式来定义的数组类型
const arr: Array<number> = [1, 2, 3]
// 模拟实现
interface IArray<T> {
// 索引签名
// 只要是 number 类型的键都可以出现在数组中,或者说数组中可以有任意多个元素
// 同时也符合数组索引是 number 类型这一前提
[key: number]: T
}
const arr: IArray<string> = ['a', 'b']
3.泛型函数
定义时宽泛、不确定的类型,需要使用者去主动传入
function id<Type>(value: Type): Type {
return value
}
const num = id<number>(10)
const str = id<string>('a')
//就是把<number>传给<type>
//简化
let num = id(10) // 省略 <number> 调用函数
let str = id('a') // 省略 <string> 调用函数
4.泛型工具
Partial
作用:都变为可选,加上?
type Props = {
id: string
children: number[]
}
type PartialProps = Partial<Props> //Partial 可选
Required
作用:都变为必选,去掉?
type Props = {
id?: string
children?: number[]
}
type PartialProps = Required<Props> //Requored 必选
ReadOnly
作用:变为只读
type Props = {
id: string
children: number[]
}
type ReadonlyProps = Readonly<Props> //Readonly 只读
let props: ReadonlyProps = { id: '1', children: [] }
props.id = '2'
//此时的props.id = '2'是无法将id改为2的,因为设置了只读的泛型工具,只允许你读取,无法修改
Pick
作用:选择一组属性构造新类型,过滤掉不使用的属性
两个变量:1.表示选择谁的属性,2.表示选择哪几个属性
interface Props {
id: string
title: string
children: number[]
}
// 摘出 id 和 title
type PickProps = Pick<Props, 'id' | 'title'>
Omit
作用:与pick相反,过滤掉选择的属性,使用不选择的属性
// 排除 id 和 title
type OmitProps = Omit<Props, 'id' | 'title'>