我目前正在开发一个ReactJS项目,该项目使用Webpack2和TypeScript。一切都运行得非常完美,但有一件事——我找不到一种方法将我自己编写的接口移动到单独的文件中,以便整个应用程序都可以看到它们。
为了原型设计目的,我最初在使用它们的文件中定义了接口,但最终我开始添加一些在多个类中需要的接口,这就是所有问题开始的地方。无论我对tsconfig.json
做出什么更改,也无论我把文件放在哪里,我的IDE和Webpack都会抱怨找不到名称("Could not find name '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"
]
}
如您所见,我的 tsconfig.json
文件位于项目目录的根目录下,所有源代码在 ./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
在TypeScript中使用
--isolatedModules
模块标志时需要注意一个额外的问题,重要的是,当使用Create React App时,默认情况下启用此标志(无法禁用) - .ts
文件必须至少导出一个内容,否则将会收到"提供'--isolatedModules'标志时,所有文件都必须是模块。"错误。这意味着将 Dictionary
接口放在没有导出关键字的 types.ts
文件中将不起作用。它必须是从 .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
N.B.
正如@dtabuenc在他的答案中提到的,环境模块(.d.ts
文件)是不鼓励使用的,我的更正不应被视为建议。这只是一种尝试,解释TypeScript中普通模块和环境模块的工作原理。
declare module MyApp { export interface Foo {} }
,并且可以通过import { {Foo} from 'MyApp'}
成功导入),但目前魔法对我来说可以工作 :) - Andris