我目前正在研究一个使用Webpack2和TypeScript的ReactJS项目。一切工作都与一件事情完全分开-我找不到一种方法来将自己编写的接口移动到单独的文件中,以使它们对整个应用程序可见。
出于原型目的,我最初在使用它们的文件中定义了接口,但最终我开始添加多个类中需要的一些接口,这就是所有问题开始的时候。无论我对我进行了什么更改tsconfig.json
,无论我将文件放在哪里,IDE和Webpack都抱怨找不到名称(“找不到名称'IMyInterface'”)。
这是我当前的tsconfig.json
文件:
{
"compilerOptions": {
"baseUrl": "src",
"outDir": "build/dist",
"module": "commonjs",
"target": "es5",
"lib": [
"es6",
"dom"
],
"typeRoots": [
"./node_modules/@types",
"./typings"
],
"sourceMap": true,
"allowJs": true,
"jsx": "react",
"moduleResolution": "node",
"rootDir": "src",
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitAny": false,
"strictNullChecks": true,
"suppressImplicitAnyIndexErrors": true,
"noUnusedLocals": true
},
"exclude": [
"node_modules",
"build",
"scripts",
"acceptance-tests",
"webpack",
"jest",
"src/setupTests.ts"
],
"types": [
"typePatches"
]
}
如您所见,mytsconfig.json
位于项目目录的根目录中,所有源位于in ./src
,我将自定义.d.ts
文件放在./typings
并包含在中typeRoots
。
我使用TypeScript 2.1.6和2.2.0对其进行了测试,但均无法正常工作。
使这一切正常工作的一种方法是将typings
目录移入src
,然后import {IMyInterface} from 'typings/blah'
对我来说感觉不合适,因为这不是我需要使用的东西。我希望这些接口在整个应用程序中都可以“神奇地”使用。
这是一个示例app.d.ts
文件:
interface IAppStateProps {}
interface IAppDispatchProps {}
interface IAppProps extends IAppStateProps, IAppDispatchProps {}
我需要export
他们还是也许declare
?我希望我不必将它们包装在名称空间中吗?
更新(2020年10月)
看到这个问题仍然令人惊讶地流行后,我想更详细地解释该解决方案。
首先,可能并应该使人们感到困惑的是,我在问题末尾给出的接口示例实际上没有任何export
关键字,即使我几乎可以肯定的是,在询问时题。我相信我没有将他们包括在内,以为他们没有任何影响,无论他们是否在那里。好吧,事实证明事实并非如此,而export
关键字恰恰是造就或破坏您能够“使用”接口而不是显式接口的关键import
。
因此,它在TypeScript中的工作方式如下:
如果您想要一个接口/类型,而不必将其导入到使用模块中,则可以简单地使用该接口/类型,该接口必须位于.ts
一个.d.ts
文件中或理想情况下位于一个文件中,而同一文件中不存在任何导入或导出。这是最重要的,因为一旦您从同一文件中导出至少一件事,它就会成为一个模块,并且该模块中的所有内容都必须由使用者随后导入。
举一个例子,假设您要具有一个Dictionary
不需要导入就可以使用的类型。声明的方式如下:
// types.d.ts
interface Dictionary {}
interface Foo {}
interface Bar {}
要使用它,您只需执行以下操作:
// consumer.ts
const dict: Dictionary = {};
但是,如果由于某种原因导出了该文件中的任何接口/类型,则它将不再起作用,例如:
// types.d.ts
interface Dictionary {}
interface Foo {}
export interface Bar {}
如果该文件中有导入,它也将不起作用:
// types.d.ts
import { OtherType } from 'other-library';
interface Dictionary {}
interface Foo extends OtherType {}
interface Bar {}
如果是这种情况,则能够使用该Dictionary
类型的唯一方法是也将其导出,然后将其导入使用者中:
// types.d.ts
export interface Dictionary {}
interface Foo {}
export interface Bar {}
// consumer.ts
import { Dictionary } from './types';
const dict: Dictionary = {};
--isolatedModules
isolatedModules
在TypeScript中使用模块标志时,要记住一个额外的怪癖,重要的是,在使用Create React App时默认启用(并且不能禁用)-.ts
文件必须至少导出一件事,否则您将得到在“设置了‘--isolatedModules’标志时,所有文件必须的模块。” 错误。这意味着将Dictionary
接口放在types.ts
没有export关键字的文件中将不起作用。它必须是.ts
文件的导出,也可能是声明,而文件中没有导出.d.ts
:
// types.d.ts
interface Dictionary {} // works
export interface Dictionary {} // works
// types.ts
interface Dictionary {} // doesn't work with --isolatedModules enabled
export interface Dictionary {} // works
注意
@dtabuenc在回答中提到,.d.ts
不建议使用环境模块(文件),我的更正不应作为建议。这只是说明普通模块和环境模块在TypeScript中如何工作的一种尝试。
interface Foo {}
声明,一切就起作用了。根据全局变量-我完全明白了为什么声明要神奇地可用是一种不好的做法,并且正在考虑切换到自定义模块(实际上已经尝试过declare module MyApp { export interface Foo {} }
并可以通过导入成功导入import { {Foo} from 'MyApp'
),但现在魔术对我有效:)