我想使用带有Typescript https://github.com/CliffCloud/Leaflet.EasyButton/blob/master/src/easy-button.js的easy-buttons插件,但它没有使用Typescript注释。
答案 0 :(得分:8)
第一步是按原样使用示例代码而不使用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)
// 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);
}
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 { };
}
}
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 { }
}
}
如果您尝试实例化一个新的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
}
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;
(从Leaflet 1.2.0开始)删除名称空间声明:
declare namespace L {
并将其替换为模块扩充:
import * as L from 'leaflet'
declare module 'leaflet' {
您的测试代码现在应该如下所示:
import * as L from 'leaflet'
import 'easy-button'
打开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
,并测试一切仍然有效。
然后提交拉取请求,以便每个人都可以从工作中受益!
答案 1 :(得分:0)
class EasyButton extends L.Control {
constructor(options?: EasyButtonOptions)
}
你的新L.EasyButton选择了一个' EasyButtonOptions'构造函数的对象。这与' L.easyButton'例子
L.easyButton有以下选项:
function easyButton(icon: string, onClick: (btn: any, map: any)=>void, title?: string, id?: string) : Control.EasyButton;
EasyButtonOptions没有' icon' onClick',' title'或者' id'相反,它需要:
interface EasyButtonOptions {
position?: ControlPosition
id?: string
type?: 'replace'|'animate'
states?: EasyButtonState[]
leafletClasses?: boolean
tagName?: string
}
因此,与L.easyButton(' fa fa-icon',()=>' ...'匹配的新L.EasyButton()相当于什么? ,'标题)?
答案 2 :(得分:0)
它实际上现在已经执行了。您应该
<=