使用.d.ts文件中的类型定义而不导入

时间:2017-05-16 12:46:48

标签: javascript typescript types import tsc

我正在将Web应用程序从普通Javascript迁移到Typescript,并使用--outFile编译器选项和/// <reference path="..."/>指令将所有单独的文件编译为单个文件。

这很好,因为我可以将代码拆分成多个文件,而不必担心支持import的浏览器。

我使用的一个库是color-js,它在名为color.d.ts的文件中有类型定义。

要使用普通的Javascript,我会执行以下操作:

的index.html:

[...]
<script src="scripts/color-js/color.js"></script>
<script src="main.js"></script> 
[...]

main.js / main.ts

let Color = net.brehaut.Color;
[...]

在运行时,这也适用于Typescript,但在编译期间,我得到如下错误:

scripts/cue.ts(4,13): error TS2304: Cannot find name 'net'. 
scripts/cue.ts(25,18): error TS2304: Cannot find name 'Color'. 
scripts/cue.ts(26,16): error TS2304: Cannot find name 'Color'.` 
scripts/cue.ts(27,19): error TS2304: Cannot find name 'Color'. 
scripts/main.ts(839,52): error TS2304: Cannot find name 'Color'. 
scripts/main.ts(1019,20): error TS2304: Cannot find name 'Color'. 
scripts/main.ts(1022,16): error TS2304: Cannot find name 'Color'.

有没有办法在color.d.ts中使用类型定义来定义编译时的类型,而不将其作为模块导入?

一旦我将它作为一个导入,我就不能再使用--outFile而且我还必须使用像RequireJS这样的东西,我没有使用它。我的浏览器不支持普通的ES6或ES5导入。

我想也许/// <reference types="..."会做那项工作,但这似乎是用于其他事情。

3 个答案:

答案 0 :(得分:4)

我的希望是为编译器抱怨的内容,原因以及解决方法提供一些可理解的上下文。不幸的是,您描述的模块导入限制可能是您要解决的另一个问题(我认为AMD和SystemJS是--outFile的唯一选择,但稍后请参阅我的移植说明。)

您在问题中引用了三斜杠指令

/// <reference types="..."

这是用于告诉编译器TS声明文件(.d.ts内的类型依赖关系的指令-并不是完全需要的,因为我们正在编写TS而不是声明文件。我们希望包括某个地方已经存在的缺少的声明文件。请注意,TypeScript确实非常努力地尝试为开发人员自动解析并包含类型声明文件,但是诸如color-js之类的库并未在其package.json中指定类型位置,也不使用类型或@types约定,编译器无法找到它。

您可能不想通过声明全局any变量来放弃您的智能优势来解决此问题。我们可以在paths编译器选项中添加一个名为tsconfig.json的犯罪记录不足的对象,这是我们通知编译器其他位置以查找类型,而不是修改诸如typesRoot或types选项。这是一个看起来运作良好的示例tsconfig.json文件:

{
    "compilerOptions": {
        "module": "system",
        "target": "es5",
        "allowJs": true,
        "outFile": "./dist/main.js",
        "rootDir": "./src",
        "baseUrl": "./",
        "paths": {
            "*": ["color-js", "./node_modules/color-js/color.d.ts"]
        }
    },
    "exclude": ["dist"]
}

paths条目告诉编译器的是,解析字符串“ color-js”的所有导入,而不是将模块解析为JS文件,而是将color.d.ts作为所需模块,而不是从指定的路径。

这是示例TS(或JS!)文件的外观:

import Color from "color-js";

let colorManager = Color();

let twenty = colorManager.setRed(20).getRed();

虽然此解决方案使用import关键字,但有一种想法是,由于我们使用上面的tsconfig.json将其转译为输出文件(读取:这是一个文件!),因此我们不必担心import关键字放入生成的main.js中。

让我们说这种配置不符合您的用例,并且您仍然发现自己正在寻找一种无需导入模块即可使用类型声明的方法。如果您真的没有其他选择,那么使用ANY变量之类的技巧是最后的选择。

在这方面,大多数声明文件是全有或全无,因为实际上从幕后.d.ts文件(包括color-js的文件)​​中导出的是一个可以构建Color实例的函数。这就是let colorManager = Color();行的全部内容,除了关于函数构建内容的类型信息之外,我们还利用了导出的构建器。正如您所注意到的,在运行时我们可能还不错,但是就编译器而言,如果我们不能导入类型化的函数并对其进行调用,则该构建将陷入困境。

答案 1 :(得分:1)

Typescript 3.8使用import type {} from '...'语法添加了此功能:

import type仅导入要用于类型注释和声明的声明。它总是会被完全擦除,因此在运行时不会有任何残留。同样,导出类型仅提供可用于类型上下文的导出,并且也会从TypeScript的输出中删除。

请务必注意,类在运行时具有值,而在设计时具有类型,并且使用对上下文敏感。使用导入类型导入类时,您不能做诸如从其扩展的事情。

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html

答案 2 :(得分:0)

如果.d.ts文件中没有很多,则可以尝试破解(虽然不是很好的做法,但可以节省时间):

declare const net: any;
declare const Color: any;
///...

在每个相关文件中的变量使用之前插入。

通常可以帮助解决不同的.d.ts问题。