如何为Leaflet插件添加Typescript定义 [英] How do I add Typescript definitions for Leaflet plugins

查看:137
本文介绍了如何为Leaflet插件添加Typescript定义的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想将Easy-buttons插件与Typescript

I would like to use easy-buttons plugin with Typescript https://github.com/CliffCloud/Leaflet.EasyButton/blob/master/src/easy-button.js and but it doesn't come with Typescript annotations.

推荐答案

步骤1-点亮错误

第一步是按原样使用没有Typescript注释的示例代码,错误将开始在VS Code中显示.

Step 1 - light up the errors

The first step is to use the sample code as-is without Typescript annotations, and the errors will start lighting up in VS Code.

// sample.ts
L.easyBar([
  L.easyButton('fa-file', function(btn, map){ }),
  L.easyButton('fa-save', function(btn, map){ }),
  L.easyButton('fa-edit', function(btn, map){ }),
  L.easyButton('fa-dot-circle-o', function(btn, map){ })
]).addTo(map);

我们为此创建了一个名为"easy-button.d.ts"的文件,并在我们的Typescript文件中对其进行引用.

To which we create a file called 'easy-button.d.ts' and refer to it in our Typescript file.

// sample.ts
import "./easy-button"
L.easyBar([
  L.easyButton('fa-file', function(btn, map){ }),
  L.easyButton('fa-save', function(btn, map){ }),
  L.easyButton('fa-edit', function(btn, map){ }),
  L.easyButton('fa-dot-circle-o', function(btn, map){ })
]).addTo(map);

easy-button.d.ts中没有任何内容

And there's nothing in easy-button.d.ts

// easy-button.d.ts
// empty for now

错误提示

error TS2339: Property 'easyBar' does not exist on type 'typeof L'.
error TS2339: Property 'easyButton' does not exist on type 'typeof L'.

这很公平,因为我们还没有定义它们.

Which is fair enough because we haven't defined these yet.

如果您引用easyBareasyButton的定义此处在这里,您会发现原始Javascript声明中发生了一些不可思议的事情.似乎这两个函数没有任何参数,但实际上它们有任何参数.

If you refer to definition of easyBar and easyButton here and here, you will find there's a bit of magic occuring in the original Javascript declarations. It appears that these two functions don't take any arguments, but in reality they do.

L.easyButton = function(/* args will pass automatically */){
  var args = Array.prototype.concat.apply([L.Control.EasyButton],arguments);
  return new (Function.prototype.bind.apply(L.Control.EasyButton, args));
};

此函数将在L.Control.EasyButton类上调用new.这些参数有些含糊,但您可以从这行给出:

This function is going to call new on the L.Control.EasyButton class. The parameters are somewhat cryptic but you can infer them from this line that gives:

initialize: function(icon, onClick, title, id)

第2步-添加类型

// easy-button.d.ts
declare namespace L {
    function easyBar();
    function easyButton();
}

现在我们离我们更近了:

and now we are a bit closer:

error TS2346: Supplied parameters do not match any signature of call target

这很明显,因为我们提供了两个参数'fa-edit'和easyButton的回调,但是我们没有在参数中声明任何内容.现在我们的第二次尝试是这样的:

and that's quite obvious because we supplied 2 parameters 'fa-edit' and a callback to easyButton but we didn't declare any in our arguments. Our second attempt now looks like this:

// easy-button.d.ts
declare namespace L {
    function easyBar(buttons: any[]);
    function easyButton(icon: string, onClick: (btn: any, map: any)=>void);
}

,现在所有的Typescript警告均已消失.但是还有更多的事情可以做.例如,easyButton实际上接受4个参数.这很容易解决-观察可选参数如何具有?后缀:

and now all the Typescript warnings have gone away. But there's more that can be done. For one, easyButton actually takes 4 arguments. That's easy to fix - observe how optional arguments have a ? suffix:

// easy-button.d.ts
declare namespace L {
    function easyBar(buttons: any[]);
    function easyButton(icon: string, onClick: (btn: any, map: any)=>void, title?: string, id?: string);
}

第3步-提供返回值

easyButton方法实际上返回一个L.Control.EasyButton实例.当前,Typescript定义暗含easyButton返回类型any.我们不想要那个!仅当我们提供打字时,打字稿才有用.

Step 3 - provide return values

The easyButton method actually returns an L.Control.EasyButton instance. Currently, the Typescript definition implies the easyButton returns type any. We don't want that! Typescript is helpful only when we provide typings.

declare namespace L {
    function easyBar(buttons: Control.EasyButton[]): Control.EasyBar;
    function easyButton(icon: string, onClick: (btn: any, map: any)=>void, title?: string, id?: string) : Control.EasyButton;

    namespace Control {
        class EasyButton { };
        class EasyBar { };
    }
}

Typescript再次开始提供有用的警告:

Typescript starts providing useful warnings again:

error TS2339: Property 'addTo' does not exist on type 'EasyBar'.

这是因为EasyBar子类L.Control,我们需要将该定义带入定义文件中.

This is because EasyBar subclasses L.Control we need to bring that definition into our definition file.

declare namespace L {
    function easyBar(buttons: Control.EasyButton[]): Control.EasyBar;
    function easyButton(icon: string, onClick: (btn: any, map: any)=>void, title?: string, id?: string) : Control.EasyButton;

    namespace Control {
        class EasyButton extends L.Control { }
        class EasyBar extends L.Control { }
    }
}

步骤4-为EasyButton和EasyBar提供构造函数参数

如果尝试实例化新的EasyButton,则代码完成建议您应传入L.ControlOptions对象以进行配置.实际上,我们需要定义自己的选项.

Step 4 - provide constructor arguments to EasyButton and EasyBar

If you try to instantiate a new EasyButton, code completion suggests that you should pass in a L.ControlOptions object to configure this. Actually we need to define our own options.

declare namespace L {
    function easyBar(buttons: Control.EasyButton[], options?: EasyBarOptions): Control.EasyBar;
    function easyButton(icon: string, onClick: (btn: any, map: any)=>void, title?: string, id?: string) : Control.EasyButton;

    interface EasyBarOptions {
        position?: ControlPosition
        id?: string
        leafletClasses?: boolean
    }

    interface EasyButtonOptions {
        position?: ControlPosition
        id?: string
        type?: 'replace'|'animate'
        states?: any
        leafletClasses?: boolean
        tagName?: string
    }

    namespace Control {
        class EasyButton extends L.Control {
            constructor(options?: EasyButtonOptions)
        }
        class EasyBar extends L.Control {
            constructor(options?: EasyBarOptions)
        }
    }
}

代码完成后情况现在看起来更好:

Things look better now on code completion:

但是,我在states选项上作弊.我声明为any.实际上应该是

However, I cheated on the states option. I declared that as any. In actuality it ought to be

    interface EasyButtonOptions {
        position?: ControlPosition
        id?: string
        type?: 'replace'|'animate'
        states?: EasyButtonState[]
        leafletClasses?: boolean
        tagName?: string
    }

    interface EasyButtonState {
        stateName: string
        onClick: () => void
        title: string
        icon: string
    }

第5步-添加jsdoc提示

Typescript将为该插件的用户提供有用的注释.这是一个示例,说明了我们如何为easyButton

   /**
     * Creates a easyButton
     * @param icon e.g. fa-globe
     * @param onClick the button click handler
     * @param label on the button
     * @param an id to tag the button with
     * @example
     * var helloPopup = L.popup().setContent('Hello World!');
     *
     * L.easyButton('fa-globe', function(btn, map){
     *      helloPopup.setLatLng(map.getCenter()).openOn(map);
     *  }).addTo( YOUR_LEAFLET_MAP );
     */
    function easyButton(
        icon: string,
        onClick: (btn: Control.EasyButton, map: L.Map) => void,
        title?: string,
        id?: string): Control.EasyButton;

步骤6进行修改以扩充传单类型定义

(从Leaflet 1.2.0开始)删除名称空间声明:

Step 6 Make modifications to augment leaflet types definitions

(Starting with Leaflet 1.2.0) Remove the namespace declaration:

declare namespace L {

并用模块增强替换它:

import * as L from 'leaflet'
declare module 'leaflet' {

您的测试代码现在应如下所示:

your test code should now read like this:

import * as L from 'leaflet'
import 'easy-button'

第7步集成到原始项目源中

打开node_modules\leaflet-easybutton\package.json,并在style条目下方添加以下行:

Step 7 integrate into the original project sources

Open up node_modules\leaflet-easybutton\package.json and add the following line below the style entry:

  "main": "src/easy-button.js",
  "style": "src/easy-button.css",
  "typings": "src/easy-button.d.ts",

将我们的easy-button.d.ts移至node_modules/leaflet-easybutton/src,并测试一切是否正常.

Move our easy-button.d.ts into node_modules/leaflet-easybutton/src, and test that everything still works.

然后提交拉取请求,以便每个人都可以从工作中受益!

Then submit a pull request so that every one can benefit from the work!

这篇关于如何为Leaflet插件添加Typescript定义的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆