【发布时间】:2012-09-23 03:48:01
【问题描述】:
我正在使用我自己和第三方的很多库。我看到“typings”目录包含一些用于 Jquery 和 WinRT...但它们是如何创建的?
【问题讨论】:
标签: typescript tsc
我正在使用我自己和第三方的很多库。我看到“typings”目录包含一些用于 Jquery 和 WinRT...但它们是如何创建的?
【问题讨论】:
标签: typescript tsc
您可以使用几个选项,具体取决于相关库、它的编写方式以及您正在寻找的准确度级别。让我们按照期望的大致降序来查看这些选项。
始终首先检查 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 编写良好并且编译器能够找到它们,那么它可能与手写文件一样好。
如果 --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 变量。
【讨论】:
--declarations 同时生成.js 文件和.d.ts 文件,这意味着您只需要运行一次编译。
--allowJs 和 --declaration 选项不能组合(在 TypeScript 1.8 和 2.0 中测试)。如果我尝试,我会得到:error TS5053: Option 'allowJs' cannot be specified with option 'declaration'
您可以像 Ryan 描述的那样使用 tsc --declaration fileName.ts,或者您可以在 tsconfig.json 中的 compilerOptions 下指定 declaration: true,前提是您的项目下已经有 tsconfig.json。
【讨论】:
tsc --declaration test.ts,我会收到错误Cannot find name...,因为我正在尝试为其创建声明文件:) 所以我需要这些类型才能声明它们?跨度>
declaration: true 添加到您的tsconfig.json 文件中吗?
处理这个问题的最好方法(如果声明文件在DefinitelyTyped 上不可用)是只为您使用的东西而不是整个库编写声明。这大大减少了工作量 - 此外,编译器可以通过抱怨缺少方法来提供帮助。
【讨论】:
正如 Ryan 所说,tsc 编译器有一个开关 --declaration,它从 .ts 文件生成 .d.ts 文件。另请注意(排除错误)TypeScript 应该能够编译 Javascript,因此您可以将现有的 javascript 代码传递给 tsc 编译器。
【讨论】:
创建自己的库时,可以使用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 文件并能够使用接口。你有例子吗?
*.d.ts 文件并将它们放在 dist/lib 文件夹中。您确实需要在项目的根目录中有一个 tsconfig.json 文件,但无论如何项目都应该在那里工作。
正如http://channel9.msdn.com/posts/Anders-Hejlsberg-Steve-Lucco-and-Luke-Hoban-Inside-TypeScript 00:33:52 中所述,他们构建了一个工具来将 WebIDL 和 WinRT 元数据转换为 TypeScript d.ts
【讨论】:
这里有一些 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 文件结束。
【讨论】:
我会寻找支持 Script# 或 SharpKit 的 3rd 方 JS 库的现有映射。这些 C# 到 .js 交叉编译器的用户将面临您现在面临的问题,并且可能已经发布了一个开源程序来扫描您的 3rd 方库并转换为骨架 C# 类。如果是这样,请破解扫描程序以生成 TypeScript 来代替 C#。
如果做不到这一点,将第 3 方库的 C# 公共接口转换为 TypeScript 定义可能比通过读取源 JavaScript 来做同样的事情更简单。
我特别感兴趣的是 Sencha 的 ExtJS RIA 框架,我知道已经发布了一些项目来为 Script# 或 SharpKit 生成 C# 解释
【讨论】:
此答案显示了如何使用 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;
};
【讨论】: