TypeScript Version: 2.0.3 / nightly (2.1.0-dev.201xxxxx)
Code
//first.d.ts
declare module 'leaflet' {
export type Point = { //same result will be with "export interface Point { constructor()..." too
new(lat:Number, lng:Number):Point;
clone(): Point;
}
}
//second.ts
import {Point} from "leaflet" //i check constants from this module are visible but exist error with usage of imported type
new Point(1,2)
AR:
error with ts 2.0.3: Cannot find name 'Point'.
error with ts 2.1.0-dev.20161023: 'Point' only refers to a type, but is being used as a value here.
This is correct - Point is just describing a _constructor_ of something, and you haven't told TypeScript that there's a value of type `Point. A type on its own just refers to the shape of a value. What you probably meant to write was something like this
export interface Point {
// ...
}
export interface PointConstructor {
new (lat: number, lng: number): Point;
clone(): Point;
}
export var Point: PointConstructor;
or simpler:
export class Point {
// members
constructor(lat: number, lng: number);
clone(): Point;
}
Also, notice I used lowercase number instead of Number, which is a common gotcha for beginners.
Thank you, it is work and thank you for advice about Number! Now the idea is clear.
I could not find explained information about typings in official documentation: case with obtained read-only object(interface), object construction(class), static methods, 'type' usage, best practises. And probably it is primitively but message is confusing...
May be do you have some links?
And can you validate it can be simplified?:
declare module 'leaflet' {
export type Leaflet = {
Point: PointStatics, //i want to describe type Point : Class<Point>(as in java) as factory of objects
}
type PointStatics = {
new(lat:Number, lng:Number):Point;
};
export class Point {
constructor(lat:Number, lng:Number); //PointStatics can be mixed in?
clone(): Point;
....
}
}
require(['leaflet'], function (L:Leaflet) {
new L.Point(1,2)
}
@gorshkov-leonid what you have is not correct
You can read about authoring declaration files from the TypeScript Handbook
But are you trying to write declarations for Leaflet as an exercise because if definitely-typed has a number of declaration files for Leaflet. You could npm i @types/leaflet or user another package manager or simply download the files manually as needed.
I will say that when I last worked with leaflet, around 6 months ago, the available typings left a lot to be desired. Leaflet is also interesting as it offers both factory and class style APIs, but typing them is still quite doable and a good exercise.
Assuming you want to write these yourself here are a few pointers.
export class Point {
constructor(lat:Number, lng:Number);
clone(): Point;
}
as @DanielRosenwasser noted you absolutely should _not_ use Number as a type annotation! you must use number instead. That is
constructor(lat: number, lng: number);
Moving on,
export type Leaflet = {
Point: PointStatics
it looks like you are trying to describe the shape of the leaflet module. For this you should use a namespace and a UMD style declaration.
// for consumers of Leaflet via it's global.
export as namespace L;
// for consumers of Leaflet using modules
export = L;
declare namespace L {
export class Point {
constructor(lat: number, lng: number, round?: number);
clone(): Point;
// add, destory, scale etc...
}
// factory function providing flexible options for creating a Point.
// arguments may be either an x and a y coordinate followed by an optional rounding value
// or an array of two numbers, [x, y] followed by an optional rounding value
// or an object containing an x and y properties followed by an optional rounding value.
// or an existing Point which will be returned as is.
export function point(x: number, y: number, round?: number): Point;
export function point(coords: [number, number] | {x: number, y: number}, round?:number): Point;
export function point(point: Point): Point;
}
Not that I have omitted JSDoc comments for brevity and that I wrote these type declarations based on reading the Leaflet's source code for Point which you can find at https://github.com/Leaflet/Leaflet/blob/master/src/geometry/Point.js.
Then to import it you can use
import { Point, point } from 'leaflet';
const p1 = new Point(1, 2);
const p2 = point([1, 2]);
or
import * as L from 'leaflet';
const p1 = new L.Point(1, 2);
const p2 = L.point({ x: 1, y: 2 });
or
import { Point, point } from 'leaflet';
require(['leaflet'], ({ Class, factory }: { Class: typeof Point, factory: typeof point }) => {
const p1 = new Class(1, 2);
const p2 = factory([1, 2], 0.23);
});
@aluanhaddad thank you for the many ways. But closer to my case I do not understand how to merge declaration http://leafletjs.com/reference-1.0.0.html#class into @types/leaflet. How to create reference to inherited static context (Marker.class -|>-Class{static addInitHook}) and use it as Marker.addInitHook(...)? It is impossible override 'interface' declaraton to 'class' without duplicates?
Are you saying you want to override the static side of a class using a derived class?
oops! I think classes and what I want - different things. Plugin in leaflet use feature with inject functionality to constructor.
MyClass.addInitHook(function () {
// ... do something in constructor additionally
// e.g. add event listeners, set custom properties etc.
});
I just wanted to make this code look similar in typescript.
export class Class {
static extend(props:any):any/* how to return constructor of self extended type ? */;
static include(props:any):any /* how to return self extended type ? */;
static mergeOptions(props:any): any /* how to return self extended type ? */;
static addInitHook(initHookFn: ()=> void): any/* how to return self extended type ? */;
}
export interface Evented extends Class{... }
export interface Layer extends Evented {...}
export interface Marker extends Layer {...}
So I want to inject hook to marker contsruction: const MyMarkerClazz:any = L.Marker.extend({...});
How to declare that new class extends L.Marker?
In my case.It seem is the file name cause the error. So I change the file name.
example:I change "legend" to "command-legend". It works!
Then how does one make those proper type checks as in @DanielRosenwasser answer, but with multi types ?
type Geometry = Point | Shape
Most helpful comment
This is correct -
Pointis just describing a _constructor_ of something, and you haven't told TypeScript that there's a value of type `Point. A type on its own just refers to the shape of a value. What you probably meant to write was something like thisor simpler:
Also, notice I used lowercase
numberinstead ofNumber, which is a common gotcha for beginners.