TypeScript 语法 + 工具封装

环境配置

安装 npm install typescript -g
查看版本 tsc --version

1.初识typescript

邂逅typescript,typescript的基本使用

新建ts 文件 (记得导出)
typescript 定义时可指定 变量类型 在名称后面加引号 和 类型
格式为 let 名称: 类型 = 值 (例如: let name:string = ‘张三’)
类型 string 首字母为小写

let message: string = '张三'
console.log(message, '------')
let name = 123
name = 66
export {}

运行 tsc xxxx 并在html中引入

<html>
   <head></head>
  <body>
    <h1>哈哈哈哈</h1>
   </body>
  <script src="xxxxx"></script>
</html>

typescript的类型推导

在 ts 中不定义 类型 会默认赋值 值的类型
例如 let name = 123 则默认 name的类型是 number
但 使用 const 赋值时 会默认返回 字面量类型
例如 const name = 1.88 则默认 name的类型是 1.88 等同于 const name:1.88 = 1.88
所以:let 推导出来的是通用类型,const推导出来的是字面量类型

2.typescript的数据类型

js中的类型

Array

//明确的指定<数组>的类型注解:两种写法
// 1.string[]: 数组类型,并且数组中存放的是字符串
let list: string[] = ['张三','李斯']
list.push('王五')
//2. Array<number> 数组类型,并且数组中存放的是number
let arr:Array<number> = [0,1,2]
arr.push(9)
export {}

Object

let info: {
    name: string
    age: number
} = {
    name: '青子',
    age: 18
}
console.log(info.name)
// 可以通过 type 定义
type infos = {
    names: string
    ages: number
}
let info1: infos = {
    names: '陆景',
    ages: 18
}
console.log(info1.ages)
export { }

使用

// z? 为可传值,不是必传
type obj = {
    x: number
    y: number
    z?: number
}

function getNum(val: obj) {
    return val.x + val.y
}

getNum({ x: 1, y: 2 })

export { }

函数的类型
参数

function getInfo(num1:number,num2:number){
    return num1 + num2
}
getInfo(5,6)
export {}

返回值

//返回值可以明确指定,也可以自动进行推导
function getInfo(num1:number,num2:number):number{
    return num1 + num2
}
let val = getInfo(5,6)
console.log(val)
export {}

匿名参数

const names = ['abc','cds','opp']
//匿名函数最好不要添加注解类型
names.forEach(function(item,index,arr){
  console.log(item,index,arr)
})
export {}

使用

type val = {
    time: number
    text: string
}
function getList(value: string) {
    let arr: val[] = []
    arr.push({ time: 111, text: '你好' })
    return arr
}

let list = getList('oioioio')
list.map(item => {
    console.log(item.time, item.text)
})
export {}

ts中的类型

any

//any表示不限制任意类型
let id: any = 44
id = "text"
id = []
console.log(id.length)
export { }

unknown

let foo:unknown = 'pp'
foo = 123
//要求必须进行类型的校验
if( typeof foo === 'string'){
    console.log(foo.length)
}
export{}

void

// 没有返回值的时候
function foo(num:number,num1:number):void{
    console.log(num+num1)
}
export {}

never

// 一般情况下不会使用never ,never表示不会返回任何值
// 封装工具的时候可以使用
function getFoo(message: number | string) {
    switch (typeof message) {
        case "string":
            console.log(message.length)
            break
        case "number":
            console.log(Number(message))
            break
        default:
            const check: never = message
    }
}
getFoo(123)
export{}

tuple

//元组类型,元组数据结构中可以存放不同的数据类型,取出来的item也是有明确的类型
const info:[string,number,number] = ['zs',18,1.88]
const value = info[1]
export{}

3. typescript的语法细节

联和类型的使用

//有的情况下一个值可能是number 也可能是string 类型,这种情况下就可以使用联合类型
let id: number | string = 123
id = 'aaa'
//范围缩小
if(typeof id === 'string'){
    console.log(id.length)
}
export{}

类型别名的使用type

// type 类型的别名
type val = number | string
let id: val = '123'
id = 456
export { }

接口声明的使用interface

//type 直接赋值
type info = {
    x: number
    y: number
    z?: number
}
//interface 声明
interface info1 {
    x: number
    y: number
    z?: number
}
function getFoo(val:info1){
  return val.x + val.y
}
getFoo({x:1,y:2})
export{}

别名和接口的区别

//区别一:type类型使用范围更广,接口类型只能用来声明对象
type info = number
type info1 = string[]
//区别二 : interface 可以多次声明,可以继承
interface Ikun {
    x: number
    y: number
}
interface Ikun {
    z?: number
}
export { }

交叉类型的使用

//交叉类型,满足两个或多个条件
interface info {
    name: string,
    age: number
}
interface Ikun {
    running: () => void
}
type NewType = info & Ikun
let list: NewType = {
    name: '张三李斯',
    age: 15,
    running: function () {
        return '你干嘛!哎哟'
    }
}
export {}

类型断言

// 获取DOM 元素  <img calss="img"/>
//使用类型断言
//类型断言规则:断言只能断言成更加具体的类型,或者不太具体(any/unknown)类型
const imgEl = document.querySelector(".img") as HTMLImageElement
imgEl.src = "xxx"
imgEl.alt = 'yyy'
export {}

非空类型断言

interface info {
    name:string
    age:18
    friend?:{
       name:string
    }
}
let foo:info = {
    name:'张三',
    age:18
}
// 访问属性:可选链:?.
console.log(foo.friend?.name)
// 属性赋值
// 解决方案一:范围缩小
if(foo.friend){
  foo.friend.name = '言念'
}
// 解决方案二:非空类型断言(有点危险,只有在确保friend 一定有值时才能使用
foo.friend!.name = '言念'
export{}

字面量类型

type utils = { url: string, method: "post"|"get" }
let request:utils = {url:'xxxx',method:'post'}
request.method as "post"
export {}

类型缩小

//1 typeof
type id = string | number
let foo: id = "123"
if (typeof foo === "string") {
    console.log(foo.length)
}
// 2 ===/!==
type Direction = "left" | "right" | "top" | "bottom"
function switchDirection(direction: Direction) {
    if (direction === "left") {
        console.log("左")
    } else if (direction === "right") {
        console.log("右")
    } else if (direction === "top") {
        console.log("上")
    }
    else if (direction === "bottom") {
        console.log("下")
    }
}
// 3 instanceof 传入一个日期,打印日期
function printDate(date: string | Date) {
    if (date instanceof Date) {
        console.log(date.getTime())
    } else {
        console.log(date)
    }
}
// 4 in 判断是否有一个属性
interface Iswim {
    swim: () => void
}
interface Irun {
    run: () => void
}
function move(animal: Irun | Iswim) {
    if ("swim" in animal) {
        animal.swim()
    } else if ("run" in animal) {
        animal.run()
    }
}
const fish: Iswim = {
    swim: function () { }
}
const dog: Irun = {
    run: function () { }
}
move(dog)
export { }

4.TypeScript函数类型

函数类型的表示方法

//方案一: 函数类型表达式 function type expression
//格式: (参数列表) => 返回值
type BarType = (num: number) => number
const bar: BarType = (aa: number): number => {
  return 123
}
export { }

函数的表达方式

type BarType = (num1: number, num2: number) => number
function calc(calcFn: BarType) {
    const num1 = 10
    const num2 = 20
    const res = calcFn(num1, num2)
    console.log(res)
}
function add(num1: number, num2: number) {
    return num1 + num2
}
calc(add)
//匿名函数
calc(function (num1, num2) {
    return num1 * num2
})
export { }

函数的类型-调用签名

// 1.函数类型表达式
type BarType = (aa: number) => number
const bar: BarType = (val: number): number => {
    return 123
}
// 2. 函数的调用签名
interface IBar {
    name: string
    age: number
    //函数可以调用:函数调用签名
    (num: number): number
}
const bar1: IBar = (val: number): number => {
    return 123
}
bar1.name = 'pp'
bar1.age = 15
bar1(123)
export { }

函数的参数-可选参数

// y?是可选参数  类型为 number | undefined
function foo(x:number,y?:number){
    return x
}
foo(10)
export {}

函数的参数-参数默认值

// 函数的参数可以有默认值
// 1. 有默认值的情况下,参数的类型注解可以省略
// 2. 有默认值的参数,是可以接收一个 undefined 的值
function foo(x:number, y=100){
    console.log(x)
}
foo(10)
foo(20,undefined)
foo(10,30)
export{}

函数的参数-剩余参数

type val = (string | number)[]
function foo(...ages: val) {
    console.log('----')
}
foo(123,'name')
export {}

函数的重载

// typescript 中函数的重载方法
// 1.先编写重载签名
//2 编写通用的函数实现
function add(x: number, y: number): number
function add(x: string, y: string): string

function add(x: any, y: any): any {
    return x + y
}
add(10, 30)
add('a', 'r')
export { }

5.TypeScript面向对象

ts中类的基本使用

class Person{
    name!: string
    age!: number
    constructor(name:string,age:number){
        this.name = name
        this,age = age
    }
}
const p1 = new Person('张文',15)
console.log(p1.name,p1.age)
export {}

ts中类的成员修饰符

// public    默认
// private   只能在类中使用
// protected 只能在类中使用,子类也可访问
class Person {
    protected name: string
    private age: number
    constructor(name: string, age: number) {
        this.name = name
        this.age = age
    }
    private eating() {
        console.log('吃东西', this.age)
    }
}
class tt extends Person {
    constructor(name: string, age: number) {
        super(name, age)
    }
    yy() {
        console.log(this.name)
    }
}
export { }

ts中类的修饰符readonly

class Person{
    readonly name:string
    age:number
    constructor(name:string,age:number){
        this.name = name
        this,age = age
    }
}
const p = new Person('why',18)
console.log(p.name,p.age)
// p.name = '张三'  readonly 只读属性,不能写入
p.age = 20
export{}

ts中类的setter 和 getters

class Person {
    //私有属性:属性前面会使用_
    // 为什么设置私有属性 ,限制不合理的赋值 ,比如年龄 不可能超过 200 ,就可以在set 拦截
    private _age :number
    constructor(age:number){
        this._age = age
    }
    set age(newValue:number){
        if(newValue > 0 && newValue < 200){
            this._age = newValue
        }else{
            console.log('你的年龄挺特别!!!')
        }
    }
    get age(){
        return this._age
    }
}
const p = new Person(20)
p.age = 30
console.log(p.age)
export {}

ts中类的参数属性的使用

class Person{
    // 语法糖
    constructor(public name:string){
        this.name = name
    }
}
const p = new Person('张')
p.name = '离'
export {}

ts中抽象类和方法的使用

//抽象类
abstract class Shape {
    //getArea 方法只有声明,没有实现体
    // 实现体让子类自己实现
    // 可以将 getArea 方法定义为抽象方法:方法的前面加 abstract
    // 抽象方法必须出现在抽象类中,类前面也要加 abstract
    // 抽象类 不能 实例化
    abstract getArea()
}
// 矩形面积
class jx extends Shape {
    constructor(public x: number, public y: number) {
        super()
    }
    getArea() {
        return this.x * this.y
    }
}
// 三角形面积
class sjx extends Shape {
    constructor(public w: number, public h: number) {
        super()
    }
    getArea() {
        return (this.w * this.h) / 2
    }
}
// 通用函数
function calcArea(shape: Shape) {
    return shape.getArea()
}
calcArea(new jx(10, 20))
calcArea(new sjx(8, 10))
export { }

ts中的类型检测-鸭子类型

// TypeScript 对于类型检测的时候使用的鸭子类型
// 鸭子类型:如果一只鸟,走起来像鸭子,游起来像鸭子,看起来像鸭子,那么你可以认为它就是一只鸭子
// 鸭子类型,只关心属性和行为,不关心你具体是不是对应的类型
class Person{
    constructor(public name:string, public age:number){}
}
function tt(p:Person){
    console.log(p.name,p.age)
}
tt(new Person('zs',20))
tt({name:'44',age:10})
export{}

ts对象类型的修饰符

type info = {
    name: string
    age?: number
}
interface Ikun {
    chang: string
    tao: string
    readonly rap: string
}
// ? 可选  readonly 只读
let t: info = {
    name: '张三李四'
}
let t1: Ikun = {
    chang: '情人',
    tao: '练习两年半',
    rap:'你干嘛!哎哟'
}
export { }

ts中的接口继承特性

interface XHZ {
    name: string
    age: number
}
//接口的继承
interface Ikun extends XHZ {
    slogan: string
}
let ikun: Ikun = {
    name: '蔡徐坤',
    age: 18,
    slogan: '你干嘛!哎哟'
}
export { }

ts中的接口的类实现过程

interface IKun {
    name: string
    age: number
    playBasketball: () => void
}
interface IRun {
    fn: () => void
}
class Person implements IKun, IRun {
    name: string
    age: number
    playBasketball() {}
    fn() {}
}
let IKun2 = new Person
console.log(IKun2.name, IKun2.age, IKun2.playBasketball, IKun2.fn)
export { }

ts严格字面量赋值检测

interface Iperson {
    name:string
    age:number
}
//奇怪的现象一
const obj = {
    name:'言念',
    age:18,
    height:1.88
}
let info:Iperson = obj
//奇怪的现象二
function tt(val:Iperson){

}
tt(obj)
// 解释现象
// 第一次创建的对象字面量,称之为fresh (新鲜的)
// 对于新鲜的字面量,会进行严格的类型检测,必须完全满足类型的要求(不能有多余的属性)
export{}

ts中的枚举类型

// 枚举默认值为0,向上递增,可以赋值
enum tt {
    LEFT,
    RIGHT
}
enum ttt {
    LEFT = 'LEFT',
    RIGHT = 'RIGHT'
}
let s: tt = tt.LEFT
function ss(t: ttt) {
    if (t === 'LEFT') {
        console.log('-------')
    }
}
ss(ttt.LEFT)
export { }

6.TypeScript泛型编程

泛型-类型的参数化

// 固定写死类型
function foo(name:string,age:number){
}
foo('陆青',18)
// 泛型
function IKun<Type>(val:Type):Type{
    return val
}
// 完整写法
let t1 = IKun<number>(111)
let t2 = IKun<string>('陆青')
let t3 = IKun<{name:string}>({name:'陆青'})
// 简写
let t4 = IKun(111)
let t5 = IKun('陆青')
let t6 = IKun({name:'陆青'})
export{}

泛型-传入多个类型

function Ikun<Type, Element>(val1: Type, val2: Element) {
    return '你干嘛!哎哟'
}
Ikun(10, 20)
Ikun(10, '陆青')
Ikun(10, [1, 2, 3])
export {}

泛型-泛型接口的使用

// 泛型可以赋值默认
type IKun<T = string> = {
    name:T,
    age:number,
    love:T
}
let kunkun:IKun = {
    name:'陆青',
    age:20,
    love:'打篮球'
}
let huang:IKun<number> = {
    name: 10,
    age:20,
    love:11
}
export {}

泛型-泛型类的使用

class Point<T = number>{
    x: T
    y: T
    constructor(x: T, y: T) {
        this.x = x
        this.y = y
    }
}
const p1 = new Point(1, 3)
const p2 = new Point<string>('1', '3')
export { }

泛型-泛型约束使用

interface ILength {
    length: number
}
// getLength 没必要使用泛型
function getLength(arg: ILength) {
    return arg.length
}
const p1 = getLength('123')
const p2 = getLength(['q', 'w'])
const p3 = getLength({ name: 'rr', age: 10 })
// 获取传入的内容,这个内容必须有length属性
// Type 相当于是一个变量,用于记录本次调用的类型,所以整个函数的执行周期中,一直保留着参数的类型

function getInfo<Type extends ILength>(args: Type) {
    return args
}
const p4 = getInfo('123')
const p5 = getInfo(['q', 'w'])
const p6 = getInfo({ name: 'rr', age: 10 })
export { }

泛型-泛型参数的使用约束

//传入key的类型
function getObjectProperty<O, K extends keyof O>(obj: O, key: K) {
    return obj[key]
}
//  K extends keyof O 等同于 K extends "name"|"age"|"love"  keyof获取 info所有key
const info = {
    name: '荒',
    age: 24,
    love: '最爱吃兽奶'
}
const name = getObjectProperty(info, 'name')
export { }

7.封装axios

创建一级文件夹 service ,二级文件夹config,request
service > index.ts

import { BASE_URL, TIME_OUT } from './config'
import HYRequest from './request'
const hyRequest = new HYRequest({
  baseURL: BASE_URL,
  timeout: TIME_OUT
})
export default hyRequest

config > index.ts

// 1 手动切换,有风险
// export const BASE_URL = 'xxxxxx'
// export const BASE_URL = 'xxxxxx'
// 2 vite默认提供的环境变量
// import.meta.env.MODE
console.log(import.meta.env.DEV) // 是否开发环境
console.log(import.meta.env.PROD) // 是否生产环境
console.log(import.meta.env.SSR) // 是否服务器渲染
// 3 新建.env 文件, 可以建多个(列如:.env.development(开发读取) .env.production(生产读取),命名使用VITE_ XXX,加上 .local表示不会提交到git
let BASE_URL = ''
if (import.meta.env.DEV) {
  BASE_URL = 'xxxxxx'
} else {
  BASE_URL = 'xxxxx'
}
console.log(BASE_URL)
export { BASE_URL }
export const TIME_OUT = 10000

request > index.ts

import axios from 'axios'
import type { AxiosInstance } from 'axios'
import type { HYRequestConfig } from './type'
class HYRequest {
  instance: AxiosInstance
  // request 实例 => axios 实例
  constructor(config: HYRequestConfig) {
    this.instance = axios.create(config)

    //每个instance 都添加拦截器
    this.instance.interceptors.request.use(
      (config) => {
        console.log('全局请求成功拦截')
        return config
      },
      (err) => {
        console.log('全局请求失败拦截')
        return err
      }
    )
    this.instance.interceptors.response.use(
      (res) => {
        console.log('全局响应成功拦截')
        return res
      },
      (err) => {
        console.log('全局响应失败的拦截')
        return err
      }
    )
    this.instance.interceptors.request.use(
      config.interceptors?.requestSuccessFn,
      config.interceptors?.requestFailureFn
    )
    this.instance.interceptors.response.use(
      config.interceptors?.responseSuccessFn,
      config.interceptors?.responseFailureFn
    )
  }
  //封装网络请求方法
  request<T = any>(config: HYRequestConfig<T>) {
    if (config.interceptors?.requestSuccessFn) {
      config = config.interceptors.requestSuccessFn(config)
    }
    return new Promise<T>((resolve, reject) => {
      this.instance
        .request<any, T>(config)
        .then((res) => {
          if (config.interceptors?.responseSuccessFn) {
            res = config.interceptors.responseSuccessFn(res)
          }
          resolve(res)
        })
        .catch((err) => {
          reject(err)
        })
    })
  }
  get<T = any>(config: HYRequestConfig<T>) {
    return this.request({ ...config, method: 'GET' })
  }
  post<T = any>(config: HYRequestConfig<T>) {
    return this.request({ ...config, method: 'POST' })
  }
  delete<T = any>(config: HYRequestConfig<T>) {
    return this.request({ ...config, method: 'DELETE' })
  }
  patch<T = any>(config: HYRequestConfig<T>) {
    return this.request({ ...config, method: 'PATCH' })
  }
}
export default HYRequest

request > type.ts

import type { AxiosRequestConfig, AxiosResponse } from 'axios'
export interface HYInterceptors<T = AxiosResponse> {
  requestSuccessFn: (config: AxiosRequestConfig) => AxiosRequestConfig
  requestFailureFn: (err: any) => any
  responseSuccessFn: (config: T) => T
  responseFailureFn: (err: any) => any
}
export interface HYRequestConfig<T = AxiosResponse> extends AxiosRequestConfig {
  interceptors?: HYInterceptors<T>
}

在.vue 页面使用

<script lang="ts" setup>
import HYRequest from '../../service'
HYRequest.get({
  url: '/home/multidata'
}).then((res) => {
  console.log(res)
})
</script>

效果
在这里插入图片描述

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值