类型声明

  • 声明文件可以让我们不需要将JS重构为TS,只需要加上声明文件就可以使用系统
  • 类型声明在编译的时候都会被删除,不会影响真正的代码

1 普通类型声明

// 其它类型声明
declare let name: string; // 变量
declare let age: number; // 变量
declare function getName(): string; // 方法
declare class Animal { name: string }; // 类

interface Peerson { // 声明接口
  name: string
}
type Student = Peerson | string; // 声明类型

2 外部枚举

  • 外部枚举是使用 declare enum 定义的枚举类型
  • 外部枚举用来描述已经存在的类型的形状
declare const enum Seasons {
  Spring,
  Summer,
  Autumn,
  Winter
}
let seasons: Seasons[] = [
  Seasons.Spring,
  Seasons.Summer,
  Seasons.Autumn,
  Seasons.Winter,
]

3 namespace 命名空间

4 类型声明文件

  • 我们可以把类型声明放在一个单独的类型声明文件中(通常是 typings 文件夹下的 xx.d.ts 文件)
  • 可以在类型声明文件中使用类型声明
  • 文件命名规范为 *.d.ts
  • 观看类型声明文件有助于了解库的使用方式

下面举个例子:

  1. 我们在 typings 文件夹下的 jquery.d.ts 文件,进行类型声明。
  2. 配置 tsconfig.json 文件,
  3. 最后在 test.js 文件中使用:

4.1 jquery.d.ts

typings\jquery.d.ts

declare const $: (selector: string) => {
  click(): void
  width(length: number): void
}

// 如果说需要导入一个模块,是JS的,没有官方的类型声明文件,也没有第三方的类型声明文件,自己也不想为他写声明文件
declare module 'parse-headers'; // 这里用 'parse-headers' 模块举例,偷懒的写法,相当于定义它的类型是 any

4.2 tsconfig.json

  • 如果类型声明文件没有起作用,需要注意在tsconfig.json文件下的"include"配置项,
{
  "compilerOptions": {
    "module": "commonjs",
    "target": "ES2015",
    "outDir": "lib",
    // ...
  },
  "include": [ // 告诉 TS 需要编译的目录,默认会编译所有根目录下的文件
    "src/**/*", // 告诉 TS 只需要编译 src 目录下的所有 .ts 文件
    "typings/**/*" // 告诉 TS 还需要编译 typings 目录下的所有 .d.ts 文件
  ]
}

4.3 test.js

$("#root").click();
$("#root").width(100);

5 第三方声明文件

  • 可以安装使用第三方的声明文件
  • @types是一个约定的前缀,所有的第三方声明的类型库都会带有这样的前缀
  • JavaScript 中有很多内置对象,它们可以在 TypeScript 中被当做声明好了的类型
  • 内置对象是指根据标准在全局作用域(Global)上存在的对象。这里的标准是指 ECMAScript 和其它环境(比如 DOM)的标准
  • 这些内置对象的类型声明文件,就包含在 TypeScript 核心库的类型声明文件 中

5.1 使用jquery

// 对于common.js风格的模块必须使用 import * as
import * as jQuery from 'jquery';
jQuery.ajax('/user/1');

5.2 安装声明文件

cnpm i @types/jquery -S

5.3 自己编写声明文件(不太现实,太多了)

types\jquery\index.d.ts

declare function jQuery(selector: string): HTMLElement;
declare namespace jQuery{
  function ajax(url: string): void
}
export default jQuery

配置:tsconfig.json 文件

  • 果配置了paths,那么在引入包的时候会自动去paths目录里找类型声明文件
  • 在 webpack 中,我们可以通过配置 alias 的形式来为项目里的文件做映射。在tsconfig.json 中,我们同样也可以做路径的映射
  • 在 tsconfig.json 中,我们通过 "compilerOptions"里的 paths 属性来配置路径映射。
    tsconfig.json
"compilerOptions": {
  "baseUrl": "./", // 使用 paths 属性的话必须要指定 baseUrl 的值
  "paths": {
    "*": ["types/*"] // 表示在导入任何模块的时候,都先去读取 types 文件下的所有文件(这里指声明文件)
  }
}

5.4 npm声明文件可能的位置

  • node_modules/jquery/package.json
  • "types": "types/xxx/d/ts"
  • node_modules/jquery/index.d.ts
  • node_modules/@types/jquery/index.d.ts

6 扩展全局变量的类型

6.1 扩展局部变量类型

// 可以直接使用接口对已有类型进行扩展
interface String {
  double():string
}
String.prototype.double = function () {
  return this as string + this;
}
let str = '123';

console.log(str.double()) // '123123'

6.2 模块内全局扩展

declare global{
  interface String {
      double():string;
  }
}
// 声明全局表示对全局进行扩展

7 和并声明

7.1 合并类型声明

// 同一名称的两个独立声明会被合并成一个单一声明,合并后的声明拥有原先两个声明的特性。

// 同名接口合并
interface Animal {
  name:string
}
interface Animal {
  age:number
}
let a:Animal = {name:'456',age:10};

7.2 使用命名空间扩展类、方法、枚举类型

// 命名空间的合并
// 扩展类
class Form {}
namespace Form {
    export const type = 'form'
}

// 扩展方法
function getName(){}
namespace getName {
    export const type = 'form'
}

// 扩展枚举类型
enum Seasons {
  Spring = 'Spring',
  Summer = 'Summer'
}
namespace Seasons{
  export let Autum = 'Autum';
  export let Winter = 'Winter'
}

8 交叉类型合并

import { createStore, Store } from 'redux';
type StoreWithExt = Store & {
    ext:string
}
let store:StoreWithExt

8 生成声明文件

配置tsconfig.json 中 "declaration": true 生成声明文件