typescript 是具有类型语法的 javascript,是一门强类型的编程语言
- ts = js + type(类型)
- js 是弱类型语言,变量可以赋不同类型的值
- ts 是强类型语言,变量不能做随意类型赋值
TS的优点
- 静态类型检查,提前发现代码错误
- 良好的代码提示,提高开发效率
使用建议
- 更适合开发中大型项目
- 通用的JS代码库
- 团队协作开发
搭建编译环境
为什么需要编译环境:TS代码无法在JS引擎中运行(如浏览器、NodeJs),需要编译成JS代码才可以正常运行
1. 搭建手动编译环境(仅用于测试,可直接进行下一步)
- 全局安装 typescript 包 -> 注册 tsc 命令:npm install -g typescript
检查引擎版本:tsc -v
- 新增 hello.ts 文件,执行 tsc hello.ts 命令生成 hello.js文件
- 执行 node hello.js 运行js文件查看效果
2. 搭建工程化下的自动编译环境
2.1在终端内运行命令,创建项目
npm create vite@latest ts-pro -- --template vanilla-ts
- npm create vite@latest:创建最新版本的vite项目
- ts-pro:项目名称
- -- --template vanilla-ts创建项目使用的模版为原生TS模版
2.2 运行项目
- cd ts-pro
- npm install
- npm run dev -> 打开项目
- 在main.ts 文件内写TS代码,在浏览器内查看控制台输出的信息
实际工作中不需要我们手动编译代码,由工程化内置,自动编译
TS类型注解
概念:给变量添加类型约束,使变量只能被赋值为约定好的类型,同时可以有相关的类型提示
注:注解为全小写(如:string)
1. TS支持的常用类型注解
- JS已有类型
- 简单类型:number string boolean null undefined
- 复杂数据类型:数组 函数
- TS新增类型:联合类型、类型别名、接口(interface)、字面量类型、泛型、枚举、void、any 等
2. 语法
2.1 注解数组
语法一(推荐):
- 类型[ ]
- 如:arr1: number[] = [1, 2, 3]
语法二:
- 泛型写法
- 如:arr2: Array<number> = [1, 2, 3]
2.2 联合类型(较复杂,通常用 类型别名 来简化)
- 作用:将多个类型连合成一个类型对变量进行注解
- 如:arr: (number | string)[] = [1, 2, 3, '1', '2', '3']
2.3 类型别名
- 通过type关键词给写起来较复杂的类型起一个其它的名字
- 好处:用来 简化 和 复用 类型
type ItemType = (string | number)[]
const arr: ItemType = ['aaa', 100]
2.4 函数类型
概念:给函数添加类型注解,本质上是给函数的 参数和返回值 添加类型约束
- 参数注解类型后不但限制了参数的类型还限制参数为必传
- 返回值注解后限制了函数内部return出去的值必须满足类型要求
好处:
- 避免因为参数不对导致的内部逻辑错误
- 对函数起到说明的作用
类型:
1. 函数声明
function add(a: number, b: number): number {
return a + b
}
add(1, 2)
let res: number
res = add(3, 4)
2. 函数表达式
1. 参数和返回值分开注解
const add1 = (a: number, b: number): number => {
return a + b
}
add1(3, 4)
2. 函数整体注解(只针对于函数表达式)- 通常在库文件里使用
type AddFn = (a: number, b: number) => number
const add2: AddFn = (a, b) => {
return a + b
}
add2(1, 2)
可选参数:(必须在所有参数的末尾)
概念:当前参数可传可不传,一旦传递参数必须保证参数类型正确
function buileName(firstName: string, lastName?: string): string {
if (lastName) {
return `${firstName}${lastName}`
} else {
return firstName
}
}
console.log(buileName('foo'));
console.log(buileName('foo', 'bar'));
无返回值:
概念:有些函数只有功能没有返回值是可以用void进行返回值注解,明确表示函数没有函数值
注:在JS中如果没有返回值,默认返回undefined,在TS中void和undefined不是一回事,undefined在TS中是一种明确的简单类型,如果指定返回值为undefined,那返回值必须是undefined类型
function eachArr(arr:number[]):void{
arr.forEach((item)=>{
console.log(item);
})
}
2.5 interface接口类型
作用:在TS中使用interface接口来描述对象数据的类型(常用于给对象的属性和方法添加类型约束)。限制的是接口的属性和对象的类型
注:一旦注解接口类型后对象的属性和方法类型都需要满足要求,属性不能多也不能少
典型场景:比较典型的是前后端数据通信的场景
- 前端向后端发送数据:收集表单对象数据是的类型校验
- 前端使用后端数据:渲染后端对象数组列表是的智能提示
interface Person {
name: string
age: number
}
const amtb: Person = {
name: 'amtb',
age: 18
}
可选设置:
概念:通过 ? 对属性进行可选标注,赋值的时候该属性可以缺失,如果有值必须保证类型满足要求
interface Props {
type: string
size?: string
}
let props: Props = {
type: 'success',
}
props = {
type: 'success',
size: 'large'
}
继承:
概念:接口的属性是可以进行类型复用的。使用 extends 实现接口继承,实现类型复用。解决接口复用问题
interface GoodsType {
id: string,
price: number
}
interface DisGoodsType extends GoodsType {
disPrice: number
}
let goods: DisGoodsType = {
id: '1001',
price: 200,
disPrice: 180
}
嵌套结构:先里后外的方式进行定义
interface Data {
title: string
content: string
}
interface resData {
code: number
msg: string
data: Data
}
let resData = {
code: 200,
msg: 'success',
data: {
title: 'aaa',
content: 'bbb'
}
2.6 type注解对象类型
概念:对象数据类型注解除interface外还可以使用类型别名进行注解,作用类似
区别:type定义时需要加 =
type Person = {
name: string
age?: number
}
let p: Person = {
name: 'amtb',
}
p = {
name: 'amtb',
age: 18
}
继承:type + 交叉类型模拟继承 - 类型别名配合交叉类型(&)
type GoodsType = {
id: string
price: number
}
type DisGoodsType = GoodsType & {
disPrice: number
}
let goods: DisGoodsType = {
id: '1001',
price: 200,
disPrice: 180
}
interface 和 type 对比:推荐使用type(更灵活)
相同:
- 都能描述对象类型
- 都能实现继承
- interface使用extends
- type配合交叉类型 &
不同:
- type除了能描述对象,还可以用来自定义其它类型
- 同名的interface会合并(属性取并集,不能出现类型冲突),同名type会报错
// 同名的interface - 合并
interface Item {
name: string
}
interface Item {
age: number
}
let item: Item = {
name: 'amtb',
age: 18
}
// 同名的type - 报错
type Item1={}
type Item1={}
2.7 字面量类型
概念:使用js字面量作为类型对变量进行类型注解,这种类型就是字面量类型
优势:类型更加精确,提供精确的可选值范围
实际应用:通常和联合类型结合起来使用,提供一个精确的可选范围
2.8 类型推论
概念:在TS中存在类型推断机制,在没有给变量添加类型注解的情况下,TS也会给变量提供类型
建议:
- 开发项目时,能省略类型注解的地方就省略
- 刚开始学TS,建议所有类型都加上,先熟悉
- 鼠标放至变量上,VsCode会自动提示类型
2.9 any类型
作用:变量被注解为any类型之后,TS会忽略类型检查,错误的类型赋值不会报错,也不会有任何提示
注:尽量避免使用any。any使用的越多,程序可能出现的漏洞越多
2.10 泛型接口:<T>
概念:在定义接口、函数等类型的时候,不预先指定具体的类型,而是在使用时再指定类型
优点:增加类型的复用性和灵活性
语法:在接口类型名称后面使用<T>即可声明一个泛型参数,接口里的其他成员都能使用该参数的类型
实现的基本方法:
- 定义参数:找到可变的类型部分通过泛型<T>抽象为泛型函数
- 传惨在使用泛型时,把具体类型传入到泛型参数位置
interface User {
name: string
age: number
}
interface Goods {
id: string,
price: number
}
interface ResData<T> {
code: number
msg: string
data: T
}
let user: ResData<User> = {
code: 200,
msg: 'success',
data: {
name: 'amtb',
age: 18
}
}
let goods: ResData<Goods> = {
code: 200,
msg: 'success',
data: {
id: '1001',
price: 100
}
}
2.11 泛型别名
语法:在类型别名type后面使用<T>即可声明一个泛型函数,接口里的其他成员都能使用该参数的类型
type User = {
name: string
age: number
}
type Goods = {
id: string,
price: number
}
type ResData<T> = {
code: number
msg: string
data: T
}
let user: ResData<User> = {
code: 200,
msg: 'success',
data: {
name: 'amtb',
age: 18
}
}
let goods: ResData<Goods> = {
code: 200,
msg: 'success',
data: {
id: '1001',
price: 100
}
}
2.12 泛型函数
语法:在函数名称后面使用<T>即可声明一个泛型函数,整个函数中(参数、返回值、函数体)的变量都可以使用该参数的类型
function fn<T>(){}
function createArray<T>(length: number, value: T) {
let result = []
for (let index = 0; index < length; index++) {
result[index] = value
}
return result
}
createArray<string>(4, '10')
createArray<number>(4, 10)
2.13 泛型约束
作用:泛型的特点就是灵活不确定,有些时候泛型函数的内部需要访问一些特定类型的数据才有的属性,此时会有类型错误,需要通过泛型约束解决
既可以保留泛型的灵活性,又做了特定的限制
// 报错
function logLen<T>(obj: T) {
console.log(obj.length);
}
// 泛型约束
interface lengthObj {
length: number
}
function logLen1<T extends lengthObj>(obj: T) {
console.log(obj.length);
}
logLen1({ length: 10 })
logLen1(['100'])
类型断言
作用:有时候开发者比TS本身更清粗当前的类型是什么,可以使用断言(as)让类型更加精确和具体
注:类型断言只能「欺骗」TS编译器,无法避免运行时的错误,滥用类型断言可能会导致运行是错误
const link = document.getElementById('link') as HTMLAnchorElement
console.log(link.href);