Chu*_*Tey 9

第1步 - 点亮错误

第一步是按原样使用示例代码而不使用Typescript注释,错误将在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);
Run Code Online (Sandbox Code Playgroud)

我们创建了一个名为'easy-button.d.ts'的文件,并在我们的Typescript文件中引用它.

// 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);
Run Code Online (Sandbox Code Playgroud)

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

// easy-button.d.ts
// empty for now
Run Code Online (Sandbox Code Playgroud)

错误说

error TS2339: Property 'easyBar' does not exist on type 'typeof L'.
error TS2339: Property 'easyButton' does not exist on type 'typeof L'.
Run Code Online (Sandbox Code Playgroud)

这是公平的,因为我们还没有定义这些.

如果你指的定义easyBar,并easyButton 在这里这里,你会发现有一个神奇的一点在发生的历史原来的Javascript声明.似乎这两个函数没有任何参数,但实际上它们确实存在.

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));
};
Run Code Online (Sandbox Code Playgroud)

此功能会调用newL.Control.EasyButton类.参数有点神秘,但你可以从这一行推断出它们:

initialize: function(icon, onClick, title, id)
Run Code Online (Sandbox Code Playgroud)

第2步 - 添加打字

// easy-button.d.ts
declare namespace L {
    function easyBar();
    function easyButton();
}
Run Code Online (Sandbox Code Playgroud)

现在我们更接近了:

error TS2346: Supplied parameters do not match any signature of call target
Run Code Online (Sandbox Code Playgroud)

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

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

现在所有的Typescript警告已经消失了.但还有更多可以做的事情.首先,easyButton实际上需要4个参数.这很容易修复 - 观察可选参数如何具有?后缀:

// 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);
}
Run Code Online (Sandbox Code Playgroud)

第3步 - 提供返回值

easyButton方法实际上返回一个L.Control.EasyButton实例.目前,Typescript定义意味着easyButton返回类型any.我们不希望这样!打字稿仅在我们提供打字时才有用.

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 { };
    }
}
Run Code Online (Sandbox Code Playgroud)

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

error TS2339: Property 'addTo' does not exist on type 'EasyBar'.
Run Code Online (Sandbox Code Playgroud)

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

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 { }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

如果您尝试实例化一个新的EasyButton,代码完成表明您应该传入一个L.ControlOptions对象来配置它.实际上我们需要定义自己的选项.代码完成

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)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在代码完成时,事情看起来更好: 新的EasyButton代码完成

但是,我欺骗了这个states选项.我声明为any.实际上它应该是

    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
    }
Run Code Online (Sandbox Code Playgroud)

第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;
Run Code Online (Sandbox Code Playgroud)

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

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

declare namespace L {
Run Code Online (Sandbox Code Playgroud)

并用模块扩充替换它:

import * as L from 'leaflet'
declare module 'leaflet' {
Run Code Online (Sandbox Code Playgroud)

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

import * as L from 'leaflet'
import 'easy-button'
Run Code Online (Sandbox Code Playgroud)

第7步整合到原始项目源中

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

  "main": "src/easy-button.js",
  "style": "src/easy-button.css",
  "typings": "src/easy-button.d.ts",
Run Code Online (Sandbox Code Playgroud)

我们的移动easy-button.d.ts进入node_modules/leaflet-easybutton/src,并测试一切仍然有效.

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