「✍ Typescript」声明文件

166 阅读2分钟

作用

ts的编写的模块最终对外暴露时是编译为js的(各种第三方工具包、组件库..), 因此外部使用时会失去类型提示, 声明文件可以为外部提供类型提示

示例

在编译打包时的配置文件tsconfig.json中加入 declaration: true

tsconfig.build.json

{
  "compilerOptions": {
    "outDir": "dist",
    "module": "esnext",
    "target": "es5",
    "declaration": true, // here
    "jsx": "react",
    "moduleResolution":"Node",
    "allowSyntheticDefaultImports": true,
    "skipLibCheck": true
  },
  "include": [
    "src"
  ],
  "exclude": [
    "src/**/*.test.tsx",
    "src/**/*.stories.tsx",
    "src/setupTests.ts",
    "stories/**/*.svg",
    "stories/**/*.mdx"
  ]
}

exam package.json 配置

"scripts": {
    "build": "tsc -p tsconfig.build.json"
  },

这样会对所有ts/tsx文件进行d.ts生成,当然,我们也可以手动编写声明文件。

在需要类型声明的文件同目录下建立同名的d.ts并编写即可,如 button.tsx 对应 button.d.ts

编写姿势

各种编写方式

// const dom:HTMLElement = jQuery('#id') √
// const dom:string = jQuery('#id') ×
let jQuery: (selector: string) => HTMLElement; // 定义已有的变量(如npm引入的jquery,但没有引入typing文件的话,就在这里手动定义,但是现在的包一般都有typing文件了)

// const fn:sayHello = (a:string) => return a + 'hello' √
type sayHello = (a: string) => string;

// window.ga() √
interface Window {
  ga: () => void;
}

// const a = new Animal('jenson')√
// a.name = 'new name' √
// a.sayHi = ()=> 'hi' √
// const a = new Animal(10) ×
// a.name = 10 ×
// a.sayHi = () => 10 × 
declare class Animal {
  name: string;
  constructor(name: string);
  sayHi(): string;
}

// const o:OO = (name: number) => return name √
interface OO {
  name: number;
}

// const o:n1.OO = (name: string) => return name √
namespace n1 {
  interface OO {
    name: string;
  }
}

ps: 发现declare关键字写不写都能全局生效,可能编译器自动自动识别了

编写类库声明

dist/env/index.js

var regExec = function (patt) {
    return patt.exec(userAgent);
};
/**
 * 获取APP版本号
 * @return {String} 4.3.0
 */
var getAppVersion = function () {
    var res = regExec(appVersionPatt);
    return res ? res[2] : "";
};
// 是否安卓APP
var isAndroid = !!regExec(androidPatt);
// 是否iOS APP
var isIos = !!regExec(iosPatt);
// 是否在APP内
var isApp = !!regExec(isAppPatt);

export default {
    getAppVersion: getAppVersion,
    isAndroid: isAndroid,
    isIos: isIos,
    isApp: isApp,
};

dist/env/index.d.ts

declare const env: {
    getAppVersion: () => any;
    isAndroid: boolean;
    isIos: boolean;
    isApp: boolean;
};

或

declare namespace env {
  function getAppVersion(): any;
  const isAndroid: boolean;
  const isIos: boolean;
  const isApp: boolean;
}

export default env;

namespacemodule作用是一致的,但ts推荐使用namespace,避免和es的module混淆

__test__.ts

import env from "./dist/env";

let a0:boolean = env.isApp // ok
let a: string = env.isApp; // error

拓展window全局方法

有时我们引入了一些第三方包如微信sdk, 其暴露的对象wx是挂载到window上了, 直接使用会被提示找不到该对象

在根目录添加global.d.ts (随意取名)

declare interface Window {
  wx:any;
}

tsconfig.json

"compilerOptions": {
  "typeRoots": ["global.d.ts"],
  "include": ["src", "global.d.ts"] // 这里一定要包含声明文件的目录
}