TS 中 declare 的作用

115 阅读3分钟

在 TypeScript 中,declare关键字主要用于声明变量、函数、类、模块等,其作用有以下几点:

声明全局变量

  • 当使用一些在 JavaScript 中已经存在的全局变量,但 TypeScript 编译器并不知道其类型时,可以使用declare vardeclare letdeclare const来声明全局变量的类型,以便在 TypeScript 代码中进行类型检查。
  • 例如,在浏览器环境中,window对象是全局可访问的,但 TypeScript 并不知道它的具体类型,我们可以这样声明:
declare let window: Window & typeof globalThis;

声明外部模块

  • 当使用外部 JavaScript 库时,如果该库没有提供 TypeScript 的类型定义文件(.d.ts),可以使用declare module来声明模块的类型,以便在 TypeScript 项目中使用该模块。
  • 比如,对于一个名为myLibrary的外部库,没有类型定义文件,我们可以创建一个myLibrary.d.ts文件,并在其中声明模块:
declare module 'myLibrary' {
  export function myFunction(): void;
  export const myVariable: number;
}

这样,在 TypeScript 代码中就可以像使用普通模块一样引入和使用myLibrary了:

import { myFunction, myVariable } from 'myLibrary';
myFunction();
console.log(myVariable);

声明函数类型

  • 可以使用declare function来声明函数的类型,而不需要提供函数的具体实现。这在定义接口或者描述函数的类型签名时非常有用。
  • 例如,声明一个接受两个数字参数并返回一个数字的函数类型:
declare function add(a: number, b: number): number;

然后,可以像使用普通函数一样调用这个声明的函数,但需要确保在其他地方有对应的函数实现:

const result = add(1, 2);
console.log(result);

声明类类型

  • declare class用于声明类的类型,通常用于只需要使用类的类型信息,而不需要类的具体实现的情况。
  • 比如,声明一个具有name属性和sayHello方法的类类型:
declare class Person {
  name: string;
  sayHello(): void;
}

之后,可以使用这个类类型来定义变量或者作为函数参数、返回值的类型:

function greet(person: Person) {
  console.log(`Hello, ${person.name}!`);
  person.sayHello();
}

const p: Person = {
  name: 'Alice',
  sayHello() {
    console.log('Hi!');
  }
};

greet(p);

扩展已有类型

  • 通过declare可以对已有的类型进行扩展,添加新的属性或方法。
  • 例如,扩展Array类型,添加一个myCustomMethod方法:
declare global {
  interface Array<T> {
    myCustomMethod(): void;
  }
}

Array.prototype.myCustomMethod = function() {
  console.log('This is a custom method for arrays.');
};

const myArray = [1, 2, 3];
myArray.myCustomMethod();

解决循环引用问题

  • 在 TypeScript 中,当两个或多个模块之间存在循环引用时,使用declare可以打破循环引用的限制,让编译器能够正确地处理类型检查。

  • 假设存在两个文件a.tsb.ts,它们相互引用对方的类型:

    • a.ts文件内容:
import { B } from './b';

export interface A {
  b: B;
}
  • b.ts文件内容:
import { A } from './a';

export interface B {
  a: A;
}
  • 上述代码会导致循环引用错误。为了解决这个问题,可以在其中一个文件中使用declare来声明对方的类型,比如在a.ts文件中:
declare module './b' {
  export interface B {
    a: A;
  }
}

import { B } from './b';

export interface A {
  b: B;
}

总之,declare关键字在 TypeScript 中是一个非常强大的工具,它可以帮助我们更好地与 JavaScript 代码进行集成,以及在不同的模块和类型之间进行更精确的类型定义和检查。