我想将Easy-buttons插件与Typescript https://github.com/CliffCloud/Leaflet.EasyButton/blob/master/src/easy-button.js一起使用,但是它没有Typescript注释。
最佳答案
第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);
为此,我们创建了一个名为“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);
在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'.
这很公平,因为我们还没有定义它们。
如果您引用
easyBar
和easyButton
的定义here和here,您会发现原始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));
};
该函数将在
new
类上调用L.Control.EasyButton
。这些参数有些含糊,但您可以从this line推断出它们,从而得到:initialize: function(icon, onClick, title, id)
第2步-添加类型
// easy-button.d.ts
declare namespace L {
function easyBar();
function easyButton();
}
现在我们更加接近:
error TS2346: Supplied parameters do not match any signature of call target
这很明显,因为我们提供了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);
}
现在所有的 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);
}
第3步-提供返回值
easyButton
方法实际上返回L.Control.EasyButton
实例。当前,Typescript定义暗示easyButton
返回类型any
。我们不想要那个!仅当我们提供打字时, typescript 才有用。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再次开始提供有用的警告:
error TS2339: Property 'addTo' does not exist on type 'EasyBar'.
这是因为EasyBar子类为
L.Control
,我们需要将该定义带入我们的定义文件中。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
对象以对其进行配置。实际上,我们需要定义自己的选项。 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)
}
}
}
现在,代码完成情况看起来更好:
但是,我欺骗了
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
}
第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开始)删除 namespace 声明:
declare namespace L {
并将其替换为模块增强:
import * as L from 'leaflet'
declare module 'leaflet' {
您的测试代码现在应如下所示:
import * as L from 'leaflet'
import 'easy-button'
步骤7整合到原始项目源中
打开
node_modules\leaflet-easybutton\package.json
并在style
条目下方添加以下行: "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
,并测试一切仍然有效。然后提交请求请求,以便每个人都可以从工作中受益!