如何从现有的 JavaScript 库生成 .d.ts “类型”定义文件?
Posted
技术标签:
【中文标题】如何从现有的 JavaScript 库生成 .d.ts “类型”定义文件?【英文标题】:How do you produce a .d.ts "typings" definition file from an existing JavaScript library? 【发布时间】:2012-09-23 03:48:01 【问题描述】:我正在使用我自己和第三方的很多库。我看到“typings”目录包含一些用于 Jquery 和 WinRT...但它们是如何创建的?
【问题讨论】:
【参考方案1】:您可以使用几个选项,具体取决于相关库、它的编写方式以及您正在寻找的准确度级别。让我们按照期望的大致降序来查看这些选项。
也许它已经存在
始终首先检查 DefinitiveTyped (https://github.com/DefinitelyTyped/DefinitelyTyped)。这是一个包含数以千计的 .d.ts 文件的社区存储库,很可能您正在使用的东西已经存在。 您还应该检查 TypeSearch (https://microsoft.github.io/TypeSearch/),它是 NPM 发布的 .d.ts 文件的搜索引擎;这将比DefiniteTyped 有更多的定义。 一些模块也将它们自己的定义作为其 NPM 分发的一部分提供,因此在尝试编写自己的模块之前还要看看是否是这种情况。
也许你不需要一个
TypeScript 现在支持 --allowJs
标志,并将在 .js 文件中进行更多基于 JS 的推理。您可以尝试在编译中包含 .js 文件以及 --allowJs
设置,看看这是否为您提供了足够好的类型信息。 TypeScript 可以识别这些文件中的 ES5 样式类和 JSDoc cmets,但如果库以一种奇怪的方式初始化自身,则可能会出错。
开始使用--allowJs
如果--allowJs
给了你不错的结果并且你想自己编写一个更好的定义文件,你可以结合--allowJs
和--declaration
来看看TypeScript 对库类型的“最佳猜测”。这将为您提供一个不错的起点,如果 JSDoc cmets 编写良好并且编译器能够找到它们,那么它可能与手写文件一样好。
dts-gen 入门
如果 --allowJs
不起作用,您可能需要使用 dts-gen (https://github.com/Microsoft/dts-gen) 来获得一个起点。此工具使用对象的运行时形状来准确枚举所有可用属性。从好的方面来说,这往往非常准确,但该工具还不支持抓取 JSDoc cmets 以填充其他类型。你这样运行:
npm install -g dts-gen
dts-gen -m <your-module>
这将在当前文件夹中生成your-module.d.ts
。
点击贪睡按钮
如果你只是想稍后再做,暂时不用类型,现在可以在 TypeScript 2.0 中编写
declare module "foo";
这将让您 import
使用 any
类型的 "foo"
模块。如果你有一个全局的你想稍后处理,只需写
declare const foo: any;
这会给你一个foo
变量。
【讨论】:
哎呀...在许多情况下,这将成为进入的重要障碍。如果有一个工具可以根据类型推断至少输出“最佳猜测”,那就太好了。虽然这些可能不是最佳的,但至少可以随着时间的推移进行调整。 +1 - 更多好消息:--declarations
同时生成.js
文件和.d.ts
文件,这意味着您只需要运行一次编译。
流行图书馆的高质量定义集合可以在github.com/borisyankov/DefinitelyTyped找到。
“最佳猜测”工具不会比 TypeScript 中已经存在的 IntelliSense 更好。类型定义的好处是为编译器提供了比它“猜测”更多的信息。
--allowJs
和 --declaration
选项不能组合(在 TypeScript 1.8 和 2.0 中测试)。如果我尝试,我会得到:error TS5053: Option 'allowJs' cannot be specified with option 'declaration'
【参考方案2】:
您可以像 Ryan 描述的那样使用 tsc --declaration fileName.ts
,或者您可以在 tsconfig.json
中的 compilerOptions
下指定 declaration: true
,前提是您的项目下已经有 tsconfig.json
。
【讨论】:
如果你正在开发一个你想分享的 Angular 2 模块,这是最好的答案。 如果我尝试tsc --declaration test.ts
,我会收到错误Cannot find name...
,因为我正在尝试为其创建声明文件:) 所以我需要这些类型才能声明它们?跨度>
@Kokodoko,您可以尝试将declaration: true
添加到您的tsconfig.json
文件中吗?
谢谢,我只是想从 *.ts 生成 *.d.ts。【参考方案3】:
处理这个问题的最好方法(如果声明文件在DefinitelyTyped 上不可用)是只为您使用的东西而不是整个库编写声明。这大大减少了工作量 - 此外,编译器可以通过抱怨缺少方法来提供帮助。
【讨论】:
不幸的是,文档毫无希望。【参考方案4】:正如 Ryan 所说,tsc 编译器有一个开关 --declaration
,它从 .ts
文件生成 .d.ts
文件。另请注意(排除错误)TypeScript 应该能够编译 javascript,因此您可以将现有的 javascript 代码传递给 tsc 编译器。
【讨论】:
似乎当前将 *.js 文件传递到 tsc 会生成错误“读取文件“angular-resource.js”时出错:找不到文件”。因此,您必须将 *.js 文件显式重命名为 *.ts 才能使用 tsc。有关更多详细信息,请参阅此问题 - 我尝试在 angularjs 上使用它:typescript.codeplex.com/workitem/26 据我所知,tsc 可以编译任何有效的 JavaScript,但如果它不是有效的 TypeScript(编译给出警告),那么 --declarations 标志不会输出 .d.ts 文件,所以除非您的库是用 TypeScript 编写的,否则您仍然需要手动创建声明文件。【参考方案5】:创建自己的库时,可以使用tsc
(TypeScript 编译器)命令创建*.d.ts
文件,如下所示:
(假设您正在将库构建到 dist/lib
文件夹)
tsc -d --declarationDir dist/lib --declarationMap --emitDeclarationOnly
-d
(--declaration
):生成*.d.ts
文件
--declarationDir dist/lib
:生成的声明文件的输出目录。
--declarationMap
:为每个对应的“.d.ts”文件生成一个源映射。
--emitDeclarationOnly
:只发出“.d.ts”声明文件。 (没有编译的 JS)
(请参阅docs 了解所有命令行编译器选项)
或者例如在你的package.json
:
"scripts":
"build:types": "tsc -d --declarationDir dist/lib --declarationMap --emitDeclarationOnly",
然后运行:yarn build:types
(或npm run build:types
)
【讨论】:
我仍然无法弄清楚如何生成d.ts
文件并能够使用接口。你有例子吗?
上面的 npm 脚本会生成 *.d.ts
文件并将它们放在 dist/lib
文件夹中。您确实需要在项目的根目录中有一个 tsconfig.json
文件,但无论如何项目都应该在那里工作。
一旦暴露,我将无法使用它们。我有以下帖子***.com/questions/59742688,如果你能让它工作?【参考方案6】:
正如http://channel9.msdn.com/posts/Anders-Hejlsberg-Steve-Lucco-and-Luke-Hoban-Inside-TypeScript 00:33:52 中所述,他们构建了一个工具来将 WebIDL 和 WinRT 元数据转换为 TypeScript d.ts
【讨论】:
【参考方案7】:这里有一些 PowerShell,它创建了一个单一的 TypeScript 定义文件,一个包含多个 *.js
文件的库。
首先,将所有扩展名更改为.ts
。
Get-ChildItem | foreach Rename-Item $_ $_.Name.Replace(".js", ".ts")
其次,使用 TypeScript 编译器生成定义文件。会有一堆编译器错误,但我们可以忽略它们。
Get-ChildItem | foreach tsc $_.Name
最后,将所有*.d.ts
文件合并为一个index.d.ts
,删除import
语句并从每个导出语句中删除default
。
Remove-Item index.d.ts;
Get-ChildItem -Path *.d.ts -Exclude "Index.d.ts" | `
foreach Get-Content $_ | `
where !$_.ToString().StartsWith("import") | `
foreach $_.Replace("export default", "export") | `
foreach Add-Content index.d.ts $_
这以包含许多定义的单个可用index.d.ts
文件结束。
【讨论】:
第二步,Get-ChildItem | foreach tsc --declaration $_.Name 工作(添加缺少的 --declaration 参数)【参考方案8】:我会寻找支持 Script# 或 SharpKit 的 3rd 方 JS 库的现有映射。这些 C# 到 .js 交叉编译器的用户将面临您现在面临的问题,并且可能已经发布了一个开源程序来扫描您的 3rd 方库并转换为骨架 C# 类。如果是这样,请破解扫描程序以生成 TypeScript 来代替 C#。
如果做不到这一点,将第 3 方库的 C# 公共接口转换为 TypeScript 定义可能比通过读取源 JavaScript 来做同样的事情更简单。
我特别感兴趣的是 Sencha 的 ExtJS RIA 框架,我知道已经发布了一些项目来为 Script# 或 SharpKit 生成 C# 解释
【讨论】:
仅供参考:我刚刚为 Sencha/ExtJS 制作了我的第一个打字稿定义文件:github.com/andremussche/extjsTypescript/blob/master/jsondocs/… 嘿 Camel Case,我整理了一篇关于使用 ExtJs 和 typescript 的博客:blorkfish.wordpress.com/2013/01/28/using-extjs-with-typescript【参考方案9】:此答案显示了如何使用 typescript 编译器 API 在独立函数中执行此操作:
import ts from 'typescript';
function createDTsTextsFromJsFilePaths(
jsFileNames: string[]
): Record<string, string>
const options =
allowJs: true,
declaration: true,
emitDeclarationOnly: true,
;
// Create a Program with an in-memory emit
const createdFiles: Record<string, string> = ;
const host = ts.createCompilerHost(options);
host.writeFile = (fileName: string, contents: string): void =>
const dtsName = fileName.replace('.js', '.d.ts');
createdFiles[dtsName] = contents;
;
// Prepare and emit the d.ts files
const program = ts.createProgram(jsFileNames, options, host);
program.emit();
return createdFiles;
////////////// test code below here ///////////////////////////////////
import fs from 'fs'
const jsTest =
`
"use strict"
function x()
return
a: 1,
b: ()=>'hello'
`;
const jsPath = '/tmp/jstest.js';
fs.writeFileSync(jsPath, jsTest);
const createdFiles = createDTsTextsFromJsFilePaths([jsPath]);
for (const dtsName in createdFiles)
console.log('================');
console.log(dtsName);
console.log('----------------');
console.log(createdFiles[dtsName]);
执行测试给出结果
================
/tmp/jstest.d.ts
----------------
declare function x():
a: number;
b: () => string;
;
函数来源于documentation in the type script compiler API guide
【讨论】:
以上是关于如何从现有的 JavaScript 库生成 .d.ts “类型”定义文件?的主要内容,如果未能解决你的问题,请参考以下文章
如何从现有的 WSDL 和 XSD 文件生成 WCF 服务主机