一路繁花似锦绣前程
失败的越多,成功才越有价值

导航

 

一、typescript语法精讲(环境)

1、ts初体验
  • IDE语法检测原理
IDE内部会生成代码的AST树,从而分析语法的错误
  • 安装和编译ts
# 安装
npm i -g typescript
# 编译
tsc index.ts
  • ts编译的作用域
* 默认情况下所有ts文件都是在同一作用域下编译的。所以如果存在相同变量名,则编译会有冲突
* 解决冲突方式一:ts文件底部加【export {}】,表示该文件是一个模块(模块有自己的作用域)
  • ts-node搭建ts环境
# 安装
npm i -g ts-node
# 安装依赖
npm i -g tslib @types/node
# 编译并在node环境运行
ts-node index.ts
2、webpack搭建ts环境
  • 安装
npm init -y
npm i -D webpack webpack-cli
npm i -D ts-loader typescript
# 生成tsconfig.json文件
tsc --init
npm i -D webpack-dev-server
npm i -D html-webpack-plugin
  • package.json
{
  "name": "learn-ts",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack",
    "serve": "webpack serve"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "html-webpack-plugin": "^5.5.0",
    "ts-loader": "^9.2.9",
    "typescript": "^4.6.4",
    "webpack": "^5.72.0",
    "webpack-cli": "^4.9.2",
    "webpack-dev-server": "^4.8.1"
  }
}
  • webpack.config.js
const path = require("path")
const HtmlWebpackPlugin = require("html-webpack-plugin")

module.exports = {
    mode: "development",
    entry: "./src/main.ts",
    output: {
        path: path.resolve(__dirname, "./dist"),
        filename: "bundle.js"
    },
    devServer: {},
    resolve: {
        extensions: [".ts", ".js", ".cjs", ".json"]
    },
    module: {
        rules: [{
            test: /\.ts$/,
            loader: "ts-loader"
        }]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./index.html"
        })
    ]
}
  • index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ts</title>
</head>
<body>

</body>
</html>
  • main.ts
import {sum} from "./math"

const message: string = "黄婷婷"

console.log(sum(20, 30))
console.log(message)
  • math.ts
export function sum(num1: number, num2: number) {
    return num1 + num2
}

二、typescript语法精讲(类型)

1、ts变量的定义格式
/**
 * 1、变量的声明:
 *     - var/let/const 标识符: 数据类型(类型注解) = 赋值
 * 2、tslint(ts代码规范检查工具):
 *     - 安装:npm i -g tslint
 *     - 生成tslint.json:tslint --init
 * 3、基本数据类型和基本数据类型的包装类:
 *     - string:Typescript中的字符串类型
 *     - String:Javascript的字符串包装类的类型
 * 4、类型推断/推导:
 *     - 默认情况下进行赋值时,会将赋值的值的类型,作为前面标识符的类型
 */
const name: string = "黄婷婷"
const age = 18

export {}
2、javascript类型
  • number类型
let num1: number = 100// 十进制
let num2: number = 0b100// 二进制
let num3: number = 0o100// 八进制
let num4: number = 0x100// 十六进制
  • boolean类型
let bol1: boolean = true
let bol2: boolean = 1 > 2
  • string类型
let str1: string = "黄婷婷"
let str2 = `name:${str1}`
  • Array类型
let persons1: Array<string> = []// 不推荐(与jsx有冲突)
let persons2: string[] = []
  • object类型
// 尽量类型推导(object类型不要使用,访问属性会报错)
let obj: object = {
    name: "黄婷婷",
    age: 18
}
  • null和undefined类型
// null和undefined默认推导类型为any
let v1: null = null
let v2: undefined = undefined
  • symbol类型
const title1 = Symbol("黄婷婷")
const title2 = Symbol("黄婷婷")

const obj = {
    [title1]: "孟美岐",
    [title2]: "姜贞羽"
}
3、typescript类型
  • any类型
// 类型断言:as any
let message: any = "黄婷婷"
message = 18
  • unknown类型
/**
 * 1、any和unknown区别
 *     - unknown类型只能赋值给any和unknown类型
 *     - any类型可以赋值给任意类型(除了never类型)
 */
let message: unknown = "黄婷婷"
let text: unknown = message
  • void类型
function foo(): void {
    // return null或者undefined或者不return(可以返回任意类型)
}
  • never类型
function foo(): never {
    while (true) {
    }
}

function bar(): never {
    throw new Error("")
}

// 1、never类型应用场景
function handleMessage(message: string | number | boolean) {
    switch (typeof message) {
        case "string":
            break
        case "number":
            break
        case "boolean":
            break
        default:
            const check: never = message
    }
}
  • tuple类型(元组类型)
let person: [string, number] = ["黄婷婷", 18]
let name: string = person[0]

function useState<T>(state: T): [T, (newValue: T) => void] {
    let currentState = state
    const changeState = (newState: T) => {
        currentState = newState
    }
    const tuple: [T, (newState: T) => void] = [currentState, changeState]
    return tuple
}

const [counter, setCounter] = useState(18)
setCounter(20)
const [title, setTitle] = useState("黄婷婷")
const [flag, setFlag] = useState(true)

type MyFunction = () => void
const foo: MyFunction = () => {
}

export {}
4、typescript类型补充
  • 函数的参数和返回值类型
/**
 * 1、参数加类型注解
 * 2、返回值加类型注解
 * 3、在开发中,通常情况下可以不写返回值的类型(自动推导)
 */
function sum(num1: number, num2: number): number {
    return num1 + num2
}
  • 匿名函数的参数类型
// 通常情况下,在定义一个函数时,都会给参数加上类型注解的
function foo(message: string) {
}

const names = ["黄婷婷", "孟美岐", "姜贞羽"]
// item的类型可以根据上下文环境推导出来,这个时候可以不添加类型注解
// 上下文中的函数:可以不添加类型注解
names.forEach(item => {
    console.log(item.split(""))
})
  • 对象类型
// 对象类型属性之间可以,或者;隔开
function printPoint(point: { x: number, y: number; z: number }) {
    console.log(point.x)
    console.log(point.y)
    console.log(point.z)
}
  • 可选类型
function printPoint(point: { x: number, y: number, z?: number }) {
    console.log(point.x)
    console.log(point.y)
    console.log(point.z)// 不传则为undefined
}
  • 联合类型
function printId(id: number | string | boolean) {
    // 类型缩小(type narrow)
    // 类型保护(type guard)
    if (typeof id === "string") {
        // typescript可根据类型判断语句确定,id一定是string类型
        console.log(id.toUpperCase())
    } else {
        console.log(id)
    }
}
  • 可选类型和联合类型的关系
// 参数是可选类型的时候,可以传undefined
function foo(message?: string) {
    console.log(message)
}

// 参数不可以省略
function bar(message: string | undefined) {
    console.log(message)
}
  • 类型别名
// type用于定义类型别名(type alias)
type IDType = string | number | boolean
type PointType = {
    x: number
    y: number
    z?: number
}

function printId(id: IDType) {
}

function printPoint(point: PointType) {
}
  • 类型断言as
// 1、类型断言as
const el = document.getElementById("img") as HTMLImageElement;
el.src = ""

/**
 * 2、类似于java中的强制类型转换
 *     伪代码:Student extends Person;person as Student
 */

/**
 * 3、string转number
 *     伪代码:string as any as number
 */
  • 非空类型断言!
function printMessageLength(message?: string) {
    // 当没有tsconfig.json文件的时候(ts-node默认会有此文件),不加!编译依然能通过
    console.log(message!.length)
}
  • 可选链的使用
type Person = {
    name: string,// 不加,或;,则必须得换行
    friend?: {
        name: string
    }
}

const person: Person = {
    name: "黄婷婷",
    friend: {
        name: "孟美岐"
    }
}

/**
 * 1、当对象的属性不存在时,会短路,直接返回undefined
 * 2、语法是?.,所以不能name?
 * 3、?.不能在=左边
 */
console.log(person.friend?.name)
  • !!和??的作用
// 1、!!
const message = "黄婷婷"
// 相当于:Boolean(message)
console.log(!!message)

// 2、??(只判断undefined和null)
const flag = undefined
const content = flag ?? "孟美岐"
console.log(content)
  • 字面量类型
// 1、"黄婷婷"也是可以作为类型的,叫做字面量类型
// 相当于:const message = "黄婷婷"
let message: "黄婷婷" = "黄婷婷"

// 2、字面量类型的意义,就是必须结合联合类型
type Alignment = "left" | "right" | "center"
let align: Alignment = "left"
  • 字面量推理
type Method = "GET" | "POST"

function request(url: string, method: Method) {
}

type Request = {
    url: string,
    method: Method
}

// 方式一:const options: Request
// 方拾二:
// 默认情况下url和method属性为string类型,后面加as const则变为字面量类型
const options = {
    url: "https://www.dingcaiyan.com",
    method: "POST"
} as const

request(options.url, options.method)

export {}
  • 类型缩小
/**
 * 1、常见的类型保护
 *     - typeof
 *     - 平等缩小(比如===、!==)
 *     - instanceof
 *     - in
 */
// 案例一:typeof
type IDType = number | string

function printID(id: IDType) {
    if (typeof id === "string") {
        console.log(id.toUpperCase())
    } else {
        console.log(id)
    }
}

// 案例二:平等缩小(比如===、!==)
type Direction = "left" | "right"

function printDirection(direction: Direction) {
    // if else/switch case语句
    switch (direction) {
        case "left":
            console.log(direction)
            break;
        default:
            console.log(direction)
    }
}

// 案例三:instanceof
function printTime(time: number | Date) {
    if (time instanceof Date) {
        // cookie使用的是GMT(格林威治时间:GMT=UTC+0)时间
        // 北京时间:CST=UTC+8
        console.log(time.toUTCString())// 世界标准时间
    } else {
        console.log(time)
    }
}

// 案例四:in
type Fish = {
    swimming: () => void
}
type Dog = {
    running: () => void
}

function walk(animal: Fish | Dog) {
    if ("swimming" in animal) {
        animal.swimming()
    } else {
        animal.running()
    }
}

const fish: Fish = {
    swimming() {
        console.log("swimming")
    }
}
walk(fish)

三、typescript语法精讲(函数)

1、typescript函数类型
  • 概念
// 在javascript中函数是一等公民。可以作为参数,也可以作为返回值
// 1、函数作为参数时,在参数中如何编写类型
function foo() {
}

type FooFnType = () => void

function bar(fn: FooFnType) {
    fn()
}

bar(foo)

// 2、定义常量时,编写函数的类型(形参名称不能省)
type AddFnType = (num1: number, num2: number) => number
const add: AddFnType = (num1: number, num2: number) => {
    return num1 + num2
}
  • 案例
function calc(n1: number, n2: number, fn: (num1: number, num2: number) => number) {
    return fn(n1, n2)
}

const result1 = calc(20, 30, function (a1, a2) {
    return a1 + a2
})
console.log(result1)

const result2 = calc(20, 30, function (a1, a2) {
    return a1 * a2
})
console.log(result2)
2、参数的可选类型
// 可选类型是必须写在必选类型的后面的
function foo(x: number, y?: number) {
}
3、参数的默认值
// 参数顺序:必选参数, 有默认值的参数, 可选参数
function foo(x: number, y: number = 30) {
    console.log(x, y)
}

foo(20, 40)// 20 40
// 有默认值的参数,也可以传undefined
foo(20, undefined)// 20 30
foo(20)// 20 30
4、函数的剩余参数
function sum(totalNum: number, ...nums: number[]) {
    let total = totalNum;
    for (const num of nums) {
        total += num;
    }
    return total;
}

console.log(sum(10, 20))
console.log(sum(10, 20, 30))
console.log(sum(10, 20, 30, 40))
5、this的默认推导
// this是可以被推导出来的,this指向person对象
const person = {
    name: "黄婷婷",
    study() {
        console.log(this.name)
    }
}

person.study()
6、this的不明确类型
type ThisType = { name: string };

function eating(this: ThisType, message: string) {
    console.log(this.name + ":" + message);
}

const info = {
    name: "黄婷婷",
    eating: eating,
};

// 隐式绑定
info.eating("哈哈哈");

// 显示绑定
eating.call({name: "孟美岐"}, "呵呵呵")
eating.apply({name: "程潇"}, ["嘿嘿嘿"])

export {}
7、函数的重载
  • 联合类型
/**
 * 1、通过联合类型有两个缺点
 *     - 进行很多的逻辑判断(类型缩小)
 *     - 返回值的类型依然是不能确定
 * 2、联合类型和函数重载的对比:开发过程中,能使用联合类型且更简单的情况下,尽量使用联合类型
 */
function add(a1: number | string, a2: number | string) {
    if (typeof a1 === "number" && typeof a2 === "number") {
        return a1 + a2
    } else if (typeof a1 === "string" && typeof a2 === "string") {
        return a1 + a2
    }
    // return a1 + a2
}
  • 函数重载
// 函数的重载:函数的名称相同,但是参数不同的几个函数,就是函数的重载
function add(num1: number, num2: number): number;// 没函数体
function add(num1: string, num2: string): string;
function add(num1: any, num2: any): any {
    if (typeof num1 === "string" && typeof num2 === "string") {
        return num1.length + num2.length
    }
    return num1 + num2
}

const result1 = add(20, 30)
const result2 = add("黄婷婷", "孟美岐")
console.log(result1)
console.log(result2)

// 在函数的重载中,实现函数是不能直接被调用的
// add({name: "姜贞羽"}, {age: 18})

四、typescript语法精讲(类)

1、类的定义
/**
 * 1、属性必须赋初始化值
 *     - 直接赋初始化值
 *     - 通过构造函数赋初始化值
 */
class Person {
    name: string = "黄婷婷"
    age: number

    constructor(age: number) {
        this.age = age
    }

    study() {
        console.log(this.name, this.age)
    }
}

const person = new Person(18);
console.log(person)
2、类的继承
class Person {
    name: string

    constructor(name: string) {
        this.name = name
    }

    running() {
        console.log("跑步")
    }
}

class Student extends Person {
    age: number

    constructor(name: string, age: number) {
        // super()调用父类的构造器(必须在使用this之前调用一次)
        super(name);
        this.age = age
    }

    running() {
        super.running()
    }

    study() {
        console.log("学习")
    }
}
3、类的多态
class Animal {
    action() {
        console.log("animal action")
    }
}

class Dog extends Animal {
    action() {
        console.log("dog running")
    }
}

class Fish extends Animal {
    action() {
        console.log("fish swimming")
    }
}

// 通过函数重载或联合类型(animals: (Dog | Fish)[])也能实现
function makeActions(animals: Animal[]) {
    animals.forEach(animal => {
        animal.action()
    })
}

makeActions([new Dog(), new Fish()])
4、类的成员修饰符
/**
 * 1、在typescript中,类的属性和方法支持三种修饰符
 *     - public(默认,可省略):任何地方可见
 *     - private:自身类中可见
 *     - protected:自身类和子类中可见
 */
class Person {
    private name: string = "黄婷婷"
    protected age: number = 18

    printName() {
        console.log(this.name)
    }
}

class Student extends Person {
    printAge() {
        console.log(this.age)
    }
}

const student = new Student();
student.printName()
student.printAge()
5、只读属性readonly
/**
 * 1、只读属性是可以在构造器中赋值,赋值之后就不可以修改
 * 2、属性本身不能进行修改,但是如果它是对象类型,对象中的属性是可以修改
 */
class Person {
    readonly name: string
    age: number
    readonly friend?: Person

    constructor(name: string, age: number, friend?: Person) {
        this.name = name
        this.age = age
        this.friend = friend
    }
}

const person = new Person("黄婷婷", 18, new Person("孟美岐", 19));
if (person.friend) {
    person.friend.age = 20
}
console.log(person)
6、getter和setter
class Person {
    private _name: string = "黄婷婷"
    get name() {
        return this._name
    }

    set name(newName) {
        this._name = newName
    }
}

const person = new Person();
person.name = "孟美岐"
console.log(person.name)
7、类的静态成员
class Person {
    static username: string = "黄婷婷"

    static study() {
        console.log("学习")
    }
}

console.log(Person.username)
Person.study()
8、抽象类abstract
/**
 * 1、抽象方法必须在抽象类中
 * 2、子类必须实现父类的抽象方法(extends)
 * 3、抽象类不能new
 * 4、tsconfig.json默认配置,抽象方法必须指定返回值类型
 */
abstract class Shape {
    abstract getArea(): number
}
9、类的类型
class Person {
    username: string = "黄婷婷"

    study() {
        console.log("学习1")
    }
}

const p: Person = {
    username: "孟美岐",
    study() {
        console.log("学习2")
    }
}

五、typescript语法精讲(接口)

1、声明对象类型
// 1、类型别名type
/*
type InfoType = {
    readonly name: string
    age: number
    friend?: {
        name: string
    }
}*/

// 2、接口interface
interface InfoType {
    readonly name: string
    age: number
    friend?: {
        name: string
    }
}

const info: InfoType = {
    name: "黄婷婷",
    age: 18,
    friend: {
        name: "孟美岐"
    }
}

console.log(info.friend?.name)
// info.name = "姜贞羽"// 只读属性不可修改

export {}
2、索引类型
interface IProp {
    [propName: string]: any
}

const obj: IProp = {
    name: "姜贞羽",
    age: 18
}

interface IArr {
    [index: number]: any
}

const arr = ["黄婷婷", "孟美岐", "鞠婧祎"]
3、函数类型
/**
 * 1、type IPerson = { (username: string): boolean }
 * 2、type IPerson = (username: string) => boolean
 */
interface IPerson {
    (username: string): boolean
}

const person: IPerson = (username) => {
    return true
}
4、接口的继承
interface ISwim {
    swimming: () => void
}

interface IFly {
    flying: () => void
}

// 接口支持多继承(extends),类不支持多继承
interface IAction extends ISwim, IFly {
}

const action: IAction = {
    swimming() {
    },
    flying() {
    }
}
5、交叉类型
type aType = number | string
type bType = number | boolean

type cType = aType | bType // number | string | boolean
type dType = aType & bType // number
type eType = number & string // never

interface ISwim {
    swimming: () => void
}

interface IFly {
    flying: () => void
}

type MyType1 = ISwim | IFly // 实现接口之一
type MyType2 = ISwim & IFly // 接口都得实现
const obj1: MyType1 = {
    flying() {
    }
}
const obj2: MyType2 = {
    swimming() {
    },
    flying() {
    }
}
6、接口的实现
interface ISwim {
    swimming: () => void
}

interface IRun {
    running: () => void
}

class Person implements ISwim, IRun {
    running(): void {
    }

    swimming(): void {
    }
}
7、interface和type区别
/**
 * 1、使用推荐
 *     - 非对象类型使用type,比如联合类型、交叉类型、函数类型
 *     - 对象类型使用interface
 * 2、区别
 *     - interface可以重复定义,属性和方法会合并
 *     - type不可以重复定义
 */
interface Person {
    name: string
}

interface Person {
    age: number
}

// type Person = { name: string, age: number }
const person: Person = {
    name: "黄婷婷",
    age: 18
}
8、擦除(freshness)
interface IPerson {
    name: string
    age: number
}

const person = {
    name: "黄婷婷",
    age: 18,
    address: "无锡"
}

function printPerson(person: IPerson) {
    console.log(person)
}

/**
 * 1、将一个变量标识符赋值给其他的变量时(对象的引用赋值,对象字面量是不可以直接赋值的),
 *   会进行freshness擦除操作。
 * 2、多了属性address会被擦除,少了属性会报错类型不匹配
 * 3、类型限制原因,函数中不可以使用address属性,但打印依然还是会有此属性
 */
printPerson(person)

六、typescript语法精讲(枚举、泛型、模块化、类型查找)

1、枚举类型
// type Direction = "left" | "right" | "center"
/**
 * 1、枚举类型默认值从0开始递增
 * 2、可赋字符串类型值
 */
enum Direction {
    LEFT = 0,
    RIGHT,// 1
    CENTER// 2
}

// 3、类型判断了所有联合类型或枚举类型之后,default或else的类型为never
function turnDirection(direction: Direction) {
    switch (direction) {
        case Direction.LEFT:
            break
        case Direction.RIGHT:
            break
        case Direction.CENTER:
            break
        default:
            const foo: never = direction
    }
}
2、泛型
  • 类型参数化
/**
 * 1、在定义这个函数时,我不决定这些参数的类型
 *   而是让调用者以参数的形式告知,我这里的函数参数应该是什么类型
 */
function printAny<Type>(arg: Type): Type {
    return arg
}

// 明确指定类型
printAny<string>("黄婷婷")
printAny<number>(18)
// 类型推导(字面量类型)
printAny("黄婷婷")
printAny(18)
  • 多个泛型
/**
 * 1、泛型常用名称
 *     - T:type的缩写
 *     - K,V:key和value的缩写
 *     - E:element的缩写
 *     - O:object的缩写
 */
function foo<T, E>(a1: T, a2: T) {
}
  • 泛型接口
interface IPerson<T1 = string, T2 = number> {
    name: T1
    age: T2
}

// 不能类型推导。可通过赋默认类型解决
const p: IPerson = {
    name: "黄婷婷",
    age: 18
}
  • 泛型类
class Point<T> {
    x: T
    y: T

    constructor(x: T, y: T) {
        this.x = x
        this.y = y
    }
}

const p1 = new Point(255, 255)
const p2 = new Point<number>(255, 255)
const p3: Point<number> = new Point(255, 255)
  • 泛型的类型约束
interface ILength {
    length: number
}

function getLength<T extends ILength>(arg: T) {
    return arg.length
}

getLength("黄婷婷")
getLength(["黄婷婷", "孟美岐", "鞠婧祎"])
getLength({length: 3})
3、模块化开发
  • 命名空间namespace
// src/math.ts
export namespace time {
    export function format(time: number) {
        return "2022-05-06"
    }
}
export namespace price {
    export function format(price: number) {
        return "99.99"
    }
}
// src/main.ts
import {time, price} from "./math";

time.format(0)
price.format(0)
4、类型的查找
  • 概念
* typescript文件介绍
    - .ts:最终会输出.js文件,编写代码的地方
    - .d.ts:用来做类型的声明(declare),仅做类型检测
* typescript查找类型声明
    - 内置类型声明
    - 外部定义类型声明
    - 自己定义类型声明
  • 内置类型声明
* 内置类型声明是typescript自带的,帮助我们内置了javascript运行时的一些标准化api的声明文件
    - 包括比如Math、Date等内置类型,也包括dom api,比如window、document等
* 内置类型声明通常在我们安装typescript的环境中会带有的
    - https://github.com/microsoft/Typescript/tree/main/lib
  • 外部定义类型声明
* 外部类型声明通常是我们使用一些库(比如第三方库)时,需要的一些类型声明
* 这些库通常有两种类型声明方式
    - 在自己库中进行类型声明(编写.d.ts文件),比如axios
    - 通过社区的一个公有库DefinitelyTyped存放类型声明文件
        该库的github地址:https://github.com/DefinitelyTyped/DefinitelyTyped/
        该库查找声明安装方式的地址:https://www.typescriptlang.org/dt/search?search=
        比如我们安装react的类型声明:npm i @types/lodash --save-dev
  • 自己定义类型声明
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ts</title>
</head>
<body>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
<script>
    const myVariable = "黄婷婷"

    function myFunction() {
        console.log("孟美岐")
    }

    class MyClass {
        constructor(name, age) {
            this.name = name
            this.age = age
        }
    }
</script>
</body>
</html>
// src/main.ts
// 1、声明模块
import lodash from "lodash"

console.log(lodash.join(["黄婷婷", "孟美岐"]))
// 2、声明变量/函数/类
console.log(myVariable)
myFunction()
console.log(new MyClass("姜贞羽", 20))
// 3、声明文件
import gongping from "./img/gongping.png"
// 4、声明命名空间
$.ajax({})
// src/index.d.ts
// 1、声明模块
declare module "lodash" {
    export function join(arr: any[]): void;
}
// 2、声明变量/函数/类
declare const myVariable: string

declare function myFunction(): void;

declare class MyClass {
    name: string
    age: number

    constructor(name: string, age: number)
}

// 3、声明文件
declare module "*.png"
// 4、声明命名空间
declare namespace $ {
    export function ajax(settings: any): any;
}
  • 扩展全局变量
// 扩展全局变量
declare global {
  interface Window {
    defineFunctionName: () => void
  }
}

// 即使此声明文件不需要导出任何东西,仍需要导出一个空对象
export {}
posted on 2022-04-28 23:38  一路繁花似锦绣前程  阅读(76)  评论(0编辑  收藏  举报