我正在尝试在Typescript/React中使用一个简单的JS库,但是无法为其创建定义文件。该库是google-kgsearch(https://www.npmjs.com/package/google-kgsearch)。它以CommonJS样式导出单个函数。我可以成功导入并调用该函数,但无法弄清楚如何在结果回调中引用参数的类型。
这是大多数库代码:
function KGSearch (api_key) {
this.search = (opts, callback) => {
....
request({ url: api_url, json: true }, (err, res, data) => {
if (err) callback(err)
callback(null, data.itemListElement)
})
....
return this
}
}
module.exports = (api_key) => {
if (!api_key || typeof api_key !== 'string') {
throw Error(`[kgsearch] missing 'api_key' {string} argument`)
}
return new KGSearch(api_key)
}
这是我对它进行建模的尝试。大多数接口(interface)都对服务返回的结果进行建模:
declare module 'google-kgsearch' {
function KGSearch(api: string): KGS.KGS;
export = KGSearch;
namespace KGS {
export interface SearchOptions {
query: string,
types?: Array<string>,
languages?: Array<string>,
limit?: number,
maxDescChars?: number
}
export interface EntitySearchResult {
"@type": string,
result: Result,
resultScore: number
}
export interface Result {
"@id": string,
name: string,
"@type": Array<string>,
image: Image,
detailedDescription: DetailedDescription,
url: string
}
export interface Image {
contentUrl: string,
url: string
}
export interface DetailedDescription {
articleBody: string,
url: string,
license: string
}
export interface KGS {
search: (opts: SearchOptions, callback: (err: string, items: Array<EntitySearchResult>) => void) => KGS.KGS;
}
}
}
我的问题是,从另一个文件中,我无法引用搜索回调返回的KGS.EntitySearchResult数组。这是我对库的使用:
import KGSearch = require('google-kgsearch');
const kGraph = KGSearch(API_KEY);
interface State {
value: string;
results: Array<KGS.EntitySearchResult>; // <-- Does not work!!
}
class GKGQuery extends React.Component<Props, object> {
state : State;
handleSubmit(event: React.FormEvent<HTMLFormElement>) {
kGraph.search({ query: this.state.value }, (err, items) => { this.setState({results: items}); });
event.preventDefault();
}
....
}
非常感谢您提供有关如何使结果接口(interface)对我的调用代码可见而又不破坏默认导出的任何建议。
最佳答案
这里的问题很容易解决。问题在于,当您导出KGSearch
时,尚未导出包含类型的 namespace KGS
。有几种方法可以解决此问题,但我建议的一种方法是利用Declaration Merging
您的代码将更改如下
declare module 'google-kgsearch' {
export = KGSearch;
function KGSearch(api: string): KGSearch.KGS;
namespace KGSearch {
// no changes.
}
}
然后从消费代码
import KGSearch = require('google-kgsearch');
const kGraph = KGSearch(API_KEY);
interface State {
value: string;
results: Array<KGSearch.EntitySearchResult>; // works!!
}
不幸的是,每当引入环境外部模块声明时(如在全局范围内编写
declare module 'google-kgsearch'
一样),我们都会污染环境外部模块的全局命名空间(这是我所知道的)。尽管暂时不太可能在您的特定项目中引起冲突,但是这意味着,如果有人为@types
添加了google-kgsearch
程序包,而您又具有依赖关系,而该依赖关系又取决于此@types
程序包,或者google-kgsearch
是否每个人都开始交付自己的依赖关系打字,我们会遇到错误。为了解决这个问题,我们可以使用一个非环境模块来声明我们的自定义声明,但这需要更多的配置。
这是我们可以如何做的
tsconfig.json
{
"compilerOptions": {
"baseUrl": "." // if not already set
"paths": { // if you already have this just add the entry below
"google-kgsearch": [
"custom-declarations/google-kgsearch"
]
}
}
}
自定义声明/google-kgsearch.d.ts (名称无所谓,只需要匹配路径即可)
// do not put anything else in this file
// note that there is no `declare module 'x' wrapper`
export = KGSearch;
declare function KGSearch(api: string): KGSearch.KGS;
declare namespace KGSearch {
// ...
}
通过将其定义为外部模块而不是环境外部模块,这使我们免受版本冲突和传递依赖问题的困扰。
需要认真考虑的最后一件事是向krismuniz/google-kgsearch发送拉取请求,该请求将您的键入内容(第二个版本)添加到名为 index.d.ts 的文件中。另外,如果维护者不希望包含它们,请考虑通过向DefinitelyTyped发送拉取请求来创建
@types/google-kgsearch
包关于javascript - 导出CommonJS模块的其他接口(interface)(Typescript),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45404041/