Typescript 声明文件与模块
声明文件
当引入的库没有类型声明时,需要手动编写 .d.ts 文件。可以在 tsconfig.json 中通过 include 指定声明文件路径:
json
{
"include": ["./src/**/*.ts", "./src/**/*.d.ts"]
}{
"include": ["./src/**/*.ts", "./src/**/*.d.ts"]
}声明文件使用 declare 关键字。
查找声明文件
- 检查库自身是否包含
.d.ts文件 - 查找社区声明文件:
npm install @types/库名 -D - 如果都没有,手动编写声明文件
全局库
定义在 document 或 window 上的方法:
ts
// global.d.ts
declare function getTitle(): string// global.d.ts
declare function getTitle(): string模块化库
使用 import/require 的都是模块化库。
UMD 库
既可全局使用也可模块导入:
ts
// moment 是典型的 UMD 库
import moment from 'moment'// moment 是典型的 UMD 库
import moment from 'moment'修改全局模块
当在原型上添加方法时:
ts
// 源文件
String.prototype.getFirstLetter = function () {
return this[0]
}
// 声明文件(利用声明合并)
interface String {
getFirstLetter(): string
}// 源文件
String.prototype.getFirstLetter = function () {
return this[0]
}
// 声明文件(利用声明合并)
interface String {
getFirstLetter(): string
}依赖声明
依赖全局库:
ts
/// <reference types='moment'/>/// <reference types='moment'/>依赖模块:
ts
import * as moment from 'moment'import * as moment from 'moment'快捷外部模块声明
快速为模块添加声明:
ts
// typings/moment/index.d.ts
declare module 'moment'// typings/moment/index.d.ts
declare module 'moment'模块解析
通过 tsconfig.json 的 moduleResolution 设置,两种策略:
Classic 策略
查找 .ts 文件 → .d.ts 文件 → 向上一级继续查找。
Node 策略
模拟 Node.js 模块解析:.ts → .tsx → .d.ts,查找 package.json 中 types → main 字段。
解析配置项
json
{
"compilerOptions": {
"baseUrl": ".", // 基目录
"paths": { // 路径映射
"*": ["node_modules/@types", "src/typings"]
},
"rootDirs": ["src/modules", "src/ts-modules"] // 虚拟目录合并
}
}{
"compilerOptions": {
"baseUrl": ".", // 基目录
"paths": { // 路径映射
"*": ["node_modules/@types", "src/typings"]
},
"rootDirs": ["src/modules", "src/ts-modules"] // 虚拟目录合并
}
}命名空间
使用 namespace 定义,内部通过 export 导出:
ts
namespace Validation {
const isLetterReg = /^[A-Za-z]+$/
export const isNumber = /^[0-9]+$/
export const checkLetter = (val: string) => isLetterReg.test(val)
}
// 使用
/// <reference path='./a.ts'/>
Validation.checkLetter('abc')namespace Validation {
const isLetterReg = /^[A-Za-z]+$/
export const isNumber = /^[0-9]+$/
export const checkLetter = (val: string) => isLetterReg.test(val)
}
// 使用
/// <reference path='./a.ts'/>
Validation.checkLetter('abc')建议:命名空间能实现的 import 都能实现,优先使用 import。
命名空间别名
ts
namespace Shape {
export namespace Polygons {
export class Trggler {}
}
}
import polygons = Shape.Polygons
let trggler = new polygons.Trggler()namespace Shape {
export namespace Polygons {
export class Trggler {}
}
}
import polygons = Shape.Polygons
let trggler = new polygons.Trggler()声明合并
同名声明会被合并为一个:
接口合并
ts
interface Info { name: string }
interface Info { age: number }
// Info 同时有 name 和 age
// 非函数成员类型必须相同,函数成员作为重载(后面的优先级更高)interface Info { name: string }
interface Info { age: number }
// Info 同时有 name 和 age
// 非函数成员类型必须相同,函数成员作为重载(后面的优先级更高)命名空间合并
未 export 的属性在同名命名空间中无法访问:
ts
namespace Validate {
const isLength = /^[0-9]+$/
export const checkLength = () => {}
}
namespace Validate {
// 取不到 isLength
export const checkLetter = () => {}
}namespace Validate {
const isLength = /^[0-9]+$/
export const checkLength = () => {}
}
namespace Validate {
// 取不到 isLength
export const checkLetter = () => {}
}类 + 命名空间合并
类必须在命名空间前面:
ts
class Validations {
constructor() {}
public checkType() {}
}
namespace Validations {
export const numberReg = /^[0-9]+$/
}class Validations {
constructor() {}
public checkType() {}
}
namespace Validations {
export const numberReg = /^[0-9]+$/
}函数 + 命名空间合并
ts
function countUp() { countUp.count++ }
namespace countUp {
export let count = 0
}function countUp() { countUp.count++ }
namespace countUp {
export let count = 0
}枚举 + 命名空间合并
ts
enum Colors { red, green, blue }
namespace Colors {
export const yellow = 3
}enum Colors { red, green, blue }
namespace Colors {
export const yellow = 3
}声明创建实体对照
| 声明类型 | 创建命名空间 | 创建类型 | 创建值 |
|---|---|---|---|
| Namespace | ✓ | ✓ | |
| Class | ✓ | ✓ | |
| Enum | ✓ | ✓ | |
| Interface | ✓ | ||
| Type Alias | ✓ | ||
| Function | ✓ | ||
| Variable | ✓ |
Cao Note