理解TS中的declare【译】

JS迁移到TS:为第三方NPM模块(非TS开发),写一个声明文件node

做者:克里斯.托马森
Apr 13, 2017
假如,你有一个由多个NPM包组成的APP,对”常规JS项目“来讲,这不是一个问题。TS的最大优点就是静态类型检查,为了更好地利用这个优点,咱们须要在”从第三方NPM包中引入代码“时,为这些第三方NPM包增长类型声明。
TS利用声明文件,来使编译器理解模块中的变量类型和函数签名。然而,如何为这些第三方NPM包增长声明文件的方式已经变了。所以,你从网上找到的那些方法,多是过期的。
TS的2.2版本中,有了一个更加直接的方法来为这些流行的NPM包增长声明文件。你所要作的是:
npm install --save-dev @types/module
// for example:
npm install --save lodash
npm install --save-dev @types/lodash
npm包管理器将自动在’node_modules/@types'模块路径下,根据这些模块的子路劲建立一个叫’index.d.ts’的文件。这个文件(即’index.d.ts)内部不包含任何业务代码。这个文件仅仅是一个用来描述组件接口,好比类定义、类型用的。尽管增长了这个文件,这个模块在使用时,你仍是得老老实实地import进来。
注释:其实这些第三方厂商,在了解TS的趋势后,在代码库编写了‘类型声明文件’, 默认安装的时候不下载。可是能够经过@types/module的方式去代码库主动下载。es6

那若是是那些没有声明文件(即该包的供应商没有编写‘类型声明模块’)的模块怎么办?typescript

不可避免的,你的项目中总有写npm包,其供应商本没有为该包编写类型声明文件。若是要在TS文件中利用静态类型检测的好处,你就不得不在项目中本身编写这个包的声明文件。
我花了数个小时来解决这个问题。TS文档也没有跟咱们说怎么样来解决这个问题,网上找到的方法不少都是旧版的解决方法。我今天写个文档,是但愿有人能经过我写的东西,在面临相同问题时,能节约一点时间。
首先打开tsconfig.json这个文件,有一个叫typeRoots的属性,这个属性是用来定义”哪里去检索声明文件“。默认的,这个属性是不设置的;并且,在不设置的时候,这个属性是直接去搜索node_modules/@types下找声明文件。由于他只会在node_modules文件夹路径下找,而这个路径是用来存放包的,你的业务代码不会放在里面。
所以,第一步就是在咱们的项目中,增长一个文件夹用来存储咱们的声明文件。在这个项目中,咱们将使用”@types“做为存放路径,固然,你想用什么名字就什么名字。
tsconfig.json
{
"compilerOptions": {npm

"outDir": "./built",
"allowJs": true,
"noImplicitAny": true,
"strictNullChecks": true,
"target": "es6",
"module": "commonjs"

},
"include": [json

"./src/**/*"

],
"exclude": [vim

"node_modules"

]
}
这个配置中,noImplicitAny被谁知成ture,这意味着你必须明确地增长类型声明。若是你有一个须要迁移不少包的大型项目,你应该把它关掉。
̶I̶t̶ ̶a̶l̶s̶o̶ ̶a̶d̶d̶s̶ ̶t̶y̶p̶e̶R̶o̶o̶t̶s̶:̶ ̶[̶”̶@̶t̶y̶p̶e̶s̶”̶,̶ ̶”̶.̶/̶@̶t̶y̶p̶e̶s̶”̶]̶ ̶.̶ ̶T̶h̶i̶s̶ ̶t̶e̶l̶l̶s̶ ̶t̶h̶e̶ ̶T̶y̶p̶e̶S̶c̶r̶i̶p̶t̶ ̶c̶o̶m̶p̶i̶l̶e̶r̶ ̶t̶o̶ ̶l̶o̶o̶k̶ ̶f̶o̶r̶ ̶.̶d̶.̶t̶s̶ ̶f̶i̶l̶e̶s̶ ̶i̶n̶ ̶b̶o̶t̶h̶ ̶n̶o̶d̶e̶_̶m̶o̶d̶u̶l̶e̶s̶/̶@̶t̶y̶p̶e̶s̶ ̶a̶s̶ ̶w̶e̶l̶l̶ ̶a̶s̶ ̶o̶u̶r̶ ̶c̶u̶s̶t̶o̶m̶ ̶d̶i̶r̶e̶c̶t̶o̶r̶y̶ ̶.̶/̶@̶t̶y̶p̶e̶s̶.̶ Note that all the original JavaScript source files were moved into srcto facilitate TypeScript compiling.
注意,全部的原生代码被迁移到src路径下,便于TS解释器编译。
2018-02-01更新:在最新版本的TS中,不须要在tsconfig.json中单独为typeRoots设置值。
如今,咱们可以建立咱们自定义的声明文件。在这个例子中,我将展现如何为一个叫作dir-obj的NPM包编写一个声明文件,这是一个我在项目中实际碰到并解决的例子。
让咱们先建立一个项目安全

mkdir ~/dev/myproject
cd ~/dev/myproject
mkdir src
mkdir built
vim tsconfig.json函数

{
"compilerOptions": {ui

"outDir": "./built",
"module": "commonjs",
"target": "es6",
"noImplicitAny": true,
"sourceMap": false

},
"include": [code

"src/**/*"

]
}
vim src/index.ts
<paste>
import * as dirObj from 'dir-obj';
const project = dirObj.readDirectory(__dirname + '/..', {
fileTransform: (file: dirObj.File) => {

return file.fullpath;

}
});
console.log(JSON.stringify(project, null, 2));
</paste>
这个简单的文件,将实现”读取项目结构,并输出每一个文件的全路径“
在根目录下,终端中输入一下代码,把TS文件编译成ES5文件:
tsc -p .
-p指令用来告诉tsc编译器,在当前路径寻找tsconfig.json文件
警告!没法找到模块声明文件

src/index.ts(1,25): error TS7016: Could not find a declaration file for module 'dir-obj'. '/Users/chris/dev/personal/typescript-examples/node_modules/dir-obj/index.js' implicitly has an 'any' type.
在当前的设置中,ts编译器不能静态检测咱们的代码是否类型安全,所以,咱们要增长声明文件。
mkdir src/@types
mkdir src/@types/dir-obj
vim src/@types/dir-obj/index.d.ts
这里咱们在src路径下建立了@types的文件夹,以便文件在编译时被自动地引入。
咱们将为dir-obj新增一个声明文件,你的声明文件必须建在npm包同名的文件夹中。即,上图中dir-obj文件为包的同名文件夹。
建立声明文件

/// <reference types="node" />

declare module 'dir-obj' {
import { Stats } from "fs";

export interface readOptions {

filter?: RegExp | Filter,
dirTransform?: DirTransform,
fileTransform?: FileTransform

}

export type Filter = (file: File) => boolean;
export type DirTransform = (file: File, value: any) => any;
export type FileTransform = (file: File) => any;

export function readDirectory(dir: string, options?: readOptions): object;

export class File {

key: string;
readonly path: string;
readonly fullpath: string;
readonly ext: string;
readonly name: string;
readonly basename: string;

constructor(dir: string, file: string);

readonly attributes: Stats;
readonly isDirectory: boolean;
readonly isRequirable: boolean;

}}咱们在文件的开头写上”declare module ‘dir-obj’“,以明确地陈述这个声明文件所要声明的npm包。声明文件剩下的内容中,是一系列原文件中同名的函数和类。不一样的是,咱们给这些同名类和函数增长了类型信息。须要指出的是,如何解读JS原包和如何写一个类型定义,不在本文档的范畴。可是,仍是但愿对你在正确的道路上有所帮助。再次发送”编译项目“指令tsc -p .最终,再也没有报编译错误。

相关文章
相关标签/搜索