3

我想在Typescript/React中使用一個簡單的JS庫,但無法爲它創建一個定義文件。該圖書館是google-kgsearch(https://www.npmjs.com/package/google-kgsearch)。它以CommonJS風格導出單個函數。我可以成功導入並調用該函數,但無法弄清楚如何將參數的類型引用到結果回調函數中。導出用於CommonJS模塊(Typescript)的其他接口

這裏是大多數庫代碼:

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) 
} 

這裏是我的嘗試建模。大部分接口模型的服務返回的結果:

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(); 
    } 
    .... 
} 

如何使結果界面看到我的調用代碼不會弄亂默認的導出任何建議,非常非常感謝。

+0

使用'import ... = require('...');贊同CommonJS模塊。這是一個非常好的做法。 –

回答

2

這裏的問題很容易解決。問題是,在導出KGSearch時,您尚未導出包含類型的名稱空間KGS。有幾種方法去了解這一點,但一個我建議是採取Declaration Merging

優勢,您的代碼將改變,因爲從消費代碼

import KGSearch = require('google-kgsearch'); 
const kGraph = KGSearch(API_KEY); 

interface State { 
    value: string; 
    results: Array<KGSearch.EntitySearchResult>; // works!! 
} 

如下

declare module 'google-kgsearch' { 

    export = KGSearch; 

    function KGSearch(api: string): KGSearch.KGS; 
    namespace KGSearch { 
     // no changes. 
    } 
} 

然後

不幸的是,每當我們引入一個環境外部模塊聲明,就像我們在全球範圍內編寫declare module 'google-kgsearch'一樣,我們會污染amb的全局命名空間客戶端模塊(我知道這是一個滿口)。儘管暫時不太可能在您的特定項目中引起衝突,但這意味着如果某人爲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" 
     ] 
    } 
    } 
} 

定製聲明/谷歌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程序包。DefinitelyTyped

+2

謝謝,這是一個很好的答案。我沒有意識到,由於具有相同的名稱,名稱空間將被合併到導出的函數中,但它可以工作。我也會嘗試您的其他配置建議。 – Brian

+0

是的,它的必要性與CommonJS模塊和UMD風格聲明有關。否則,您可以單獨導出它們。有利的是,這爲消費者保持進口清潔。 –

+2

我會使用這些類型發送一個PR,我已經更多地使用了它們,並且更加確信api結果真的符合我的定義。再次感謝:) – Brian