TypeScript 0.9.1 CommonJS: correctly declaring exported ambient class implementing external interface? - class

EDIT:
Put another way the following within a .d.ts file shouldn't produce compiler error TS2137 'Class "MyClass" does not implement interface "IInterface"':
interface IInterface {
someMethod():void;
}
declare module "mod" {
export class MyClass implements IInterface {
constructor();
}
}
because I'm not (and can't in a declaration) implementing anything. Is this a bug in the compiler or is there some other way/syntax to do what the above implies? I would think the compiler smart enough to know to precisely include IInterface's signature as part of MyClass, and not require its methods be redeclared.
ORIGINAL:
I'm trying to write a d.ts for the node component bunyan. Having a problem with exporting a class that implements an external interface, specifically RingBuffer which extends node's EventEmitter. The problem simplified is (below in a bunyan.d.ts file):
// this interface declared in <reference..., put inline here for simplicity
interface IExternal {
inheritedMethod():void;
}
interface RingBuffer extends IExternal {
write():void;
}
declare var RingBuffer: {
new():RingBuffer;
}
declare module "bunyan" {
export var RingBuffer;
}
then used in myNodeApp.js
/// <references path="bunyan.d.ts" />
import bunyan = require( 'bunyan' );
var rb = new bunyan.RingBuffer();
// compiler doesn't error on this; thinks RingBuffer is type any.
// also, no intellisense to show write() method.
rb.badFunc();
changing bunyan.d.ts to:
declare module "bunyan" {
export class RingBuffer { constructor(); }
}
compiles, but same problem when used; no intellisense, no compile errors.
changing bunyan.d.ts to
declare module "bunyan" {
export var RingBuffer:RingBuffer;
}
causes compile error in myNodeApp.js
// error TS2083: Invalid 'new' expression
import rb = new bunyan.RingBuffer();
removing from bunyan.d.ts
declare module "bunyan" {
...
}
causes compile error in myNodeApp.js
// error TS2071: Unable to resolve external module ''bunyan''
import bunyan = require( 'bunyan' );
changing bunyan.d.ts
interface IExternal {
inheritedMethod():void;
}
interface IRingBuffer extends IExternal {
}
declare module "bunyan" {
export class RingBuffer implements IRingBuffer {}
}
cause compile error
// error TS2137: Class "bunyan".RingBuffer declares interface IRingBuffer but
// does not implement it: type '"bunyan".RingBuffer' is missing property
// 'inheritedMethod' from type 'IRingBuffer'
implying I have to redeclare all inherited methods from all extended interfaces, besides IRingBuffer, which seems a bit ridiculuous to have to do in a d.ts file
Does anyone know the 'correct' way to declare an ambient class that implements an interface for consumption in another CommonJS module??

An alternate way to define it would be the way Jquery's typescript definition is defined. You have separate interfaces for static and instance members. Here is a sample complete definition:
interface IExternal {
inheritedMethod():void;
}
interface IRingBuffer extends IExternal {
write():void;
}
// Static functions and constructors
interface IRingBufferStatic{
new():IRingBuffer;
}
declare var RingBuffer:IRingBufferStatic;
declare module "bunyan" {
export var RingBuffer:IRingBufferStatic;
}
// In the second file
import bunyan = require( 'bunyan' );
var rb = new bunyan.RingBuffer();
// you get an error here
rb.badFunc();
Try it online

Related

How can an abstract implement an interface?

I have a common interface that describes access to the output stream like this:
interface IOutput {
function writeInteger(aValue:Int):Void;
}
And I have an abstract implementation of this interface based on standard haxe.io.BytesOutput class:
abstract COutput(BytesOutput) from BytesOutput {
public inline function new(aData:BytesOutput) {
this = aData;
}
public inline function writeInteger(aValue:Int):Void {
this.writeInt32(aValue);
}
}
Though this abstract is truly implementing interface described above there's no direct reference to interface and when I'm trying to use it like this:
class Main {
public static function out(aOutput:IOutput) {
aOutput.writeInteger(0);
}
public static function main() {
var output:COutput = new BytesOutput();
out(output); // type error
}
}
Compiler throws an error: COutput should be IOutput. I can solve this problem only through using common class that wraps BytesOutput and implements IOutput.
My question is how to show the Haxe compiler that the abstract implements the interface.
Abstracts can't implement interfaces because they're a compile-time feature and don't exist at runtime. This conflicts with interfaces, they do exist at runtime and dynamic runtime checks like Std.is(something, IOutput) have to work.
Haxe also has a mechanism called structural subtyping that can be used as an alternative to interfaces. With this approach, there's no need for an explicit implements declaration, it's good enough if something unifies with a structure:
typedef IOutput = {
function writeInteger(aValue:Int):Void;
}
Unfortunately, abstracts aren't compatible with structural subtyping either due to the way they're implemented.
Have you considered using static extensions instead? At least for your simple example, that seems like the perfect solution for making a writeInteger() method available for any haxe.io.Output:
import haxe.io.Output;
import haxe.io.BytesOutput;
using Main.OutputExtensions;
class Main {
static function main() {
var output = new BytesOutput();
output.writeInteger(0);
}
}
class OutputExtensions {
public static function writeInteger(output:Output, value:Int):Void {
output.writeInt32(value);
}
}
You could even combine this with structural subtyping so writeInteger() becomes available on anything that has a writeInt32() method (try.haxe link):
typedef Int32Writable = {
function writeInt32(value:Int):Void;
}
As #Gama11 states, abstracts cannot implement interfaces. In Haxe, for type to implement an interface, it must be able to be compiled to something class-like that can be called using the interface’s methods without any magic happening. That is, to use a type as its interface, there needs to be a “real” class implementing that type. Abstracts in Haxe compile down to their base type—the abstract itself is entirely invisible after compilation happens. Thus, at runtime, there is no instance of a class with the methods defined in your abstract which implement the interface.
However, you can make your abstract appear to implement an interface by defining an implicit conversion to the interface you are trying to implement. For your example, the following might work:
interface IOutput {
function writeInteger(aValue:Int):Void;
}
abstract COutput(BytesOutput) from BytesOutput {
public inline function new(aData:BytesOutput) {
this = aData;
}
#:to()
public inline function toIOutput():IOutput {
return new COutputWrapper((cast this : COutput));
}
public inline function writeInteger(aValue:Int):Void {
this.writeInt32(aValue);
}
}
class COutputWrapper implements IOutput {
var cOutput(default, null):COutput;
public function new(cOutput) {
this.cOutput = cOutput;
}
public function writeInteger(aValue:Int) {
cOutput.writeInteger(aValue);
}
}
class Main {
public static function out(aOutput:IOutput) {
aOutput.writeInteger(0);
}
public static function main() {
var output:COutput = new BytesOutput();
out(output);
out(output);
}
}
Run on try.haxe.org
Note that, each time an implicit conversion happens, a new instance of the wrapper will be constructed. This may have performance implications. If you only access your value through its interface, consider setting the type of your variable to the interface rather than the abstract.
This is similar to “boxing” a primitive/value type in C#. In C#, value types, defined using the struct keyword, are allowed to implement interfaces. Like an abstract in Haxe, a value type in C# is compiled (by the JITter) into untyped code which simply directly accesses and manipulates the value for certain operations. However, C# allows structs to implement interfaces. The C# compiler will translate any attempt to implicitly cast a struct to an implemented interface into the construction of a wrapper class which stores a copy of the value and implements the interface—similar to our manually authored wrapper class (this wrapper class is actually generated by the runtime as part of JITing and is performed by the IL box instruction. See M() in this example). It is conceivable that Haxe could add a feature to automatically generate such a wrapper class for you like C# does for struct types, but that is not currently a feature. You may, however, do it yourself, as exemplified above.

Using haxe.macro.TypeTools fails

I'm trying to debug a library which uses haxe.macro.TypeTools::findField. I've created a simple code for that:
package;
using haxe.macro.TypeTools;
class Main
{
public function new()
{
var test = findField(Child, "hello");
trace(test);
}
}
class Base
{
private function hello()
{
}
}
class Child extends Base
{
public function new() {}
}
However I'm getting error Unknown identifier : findField. Is this because it can only be used in build macro context?
This is what I'm trying to emulate.
First of all, function findField() is not from the haxe.macro.TypeTools.
It is a helper function from edge.core.macro.Macros.
To use it without a class path, import it's class with a wildcard import edge.core.macro.Macros.*
Secondly, findField() should be used in a build macro context only, since it expects Array<Field>, which is obtained by haxe.macro.Context.getBuildFields().

How to properly bind current object context in ES6 using babelify

I'm trying to bind current instance to the class method, please note ES6 syntax.
class SomeClass {
search() => { ... }
}
Which is 100% legit code, however, babelify doesn't want to compile it
SyntaxError: /Users/vladmiller/Projects/test/test/client/test/app/pages/Search.react.js: Unexpected token (50:26) while parsing file: /Users/vladmiller/Projects/test/test/client/test/app/pages/Search.react.js\
Instead, now I have to bind context in class constructor
class SomeClass {
constructor() {
this.search = this.search.bind(this)
}
search() { ... }
}
Which is quite annoying and boring.
UPD: It turns out that this is invalid ES6 syntax; therefore the question is follows. What is the best way to bind instance context to a class method?
UPD2: By default context should be attached, however, the issue with React http://jsbin.com/citafaradu/2/edit?js,console,output
This code is not valid ES2015. Prototype methods are defined like this:
class SomeClass {
search() { /* ... */ }
}

Typescript: Cannot export a module that is a generic interface and contains other generic interfaces

I'm trying to write a CommonJS declaration file for Bluebird, a promise library that directly exports a generic Promise class. However, the library also exports several other generic classes as static members (PromiseInspection), and it seems like its impossible to model this with typescript.
Edit: Usage example, to illustrate how the module's exported class works:
import Promise = require('bluebird');
var promise:Promise<number> = Promise.cast(5);
var x:Promise.PromiseInspection<number> = promise.inspect();
I tried several strategies - simplified examples follow:
1. The obvious way
declare module "bluebird" {
class PromiseInspection<T> {
// ...
}
class Promise<T> {
PromiseInspection: typeof PromiseInspection; // error
constructor<T>();
inspect():PromiseInspection<T>; // error
static cast<U>(value:U):Promise<U>;
// ...
}
export = Promise;
}
Fails with the error unable to use private type PromiseInspection as a public property
2. Using a static interface
declare module "bluebird2" {
interface PromiseInspection<T> {
// ...
}
interface Promise<T> {
constructor<T>();
inspect():PromiseInspection<T>;
}
interface PromiseStatic {
new<T>();
PromiseInspection:typeof PromiseInspection;
cast<U>(value:U):Promise<U>; // error
}
export = PromiseStatic;
}
Also fails similarly, but this time the private type is Promise
3. Trying to directly export a constructor function from the module
declare module "bluebird3" {
export interface PromiseInspection<T> {
// ...
}
export interface Promise<T> {
constructor<T>();
inspect():PromiseInspection<T>;
}
export new<T>(); // syntax error
export function cast<U>(value:U):Promise<U>;
}
This almost works, except of course its impossible to a constructor function that way.
4. The namespace polluting way (Works, with downsides)
interface PromiseInspection<T> {
// ...
}
interface Promise<T> {
constructor<T>();
inspect():PromiseInspection<T>;
}
declare module "bluebird4" {
interface PromiseStatic {
new<T>():Promise<T>;
PromiseInspection: typeof PromiseInspection;
cast<U>(value:U):Promise<U>;
}
export = PromiseStatic;
}
Works, but it pollutes the global namespace with both Promise and PromiseInspection. This might be okay but I'd rather avoid it as in CommonJS its usually considered unacceptable.
5. With declaration merging (gets me 90% of the way...)
declare module "bluebird5" {
module Promise {
export interface PromiseInspection<T> {
value(): T;
// ...
}
export
function cast<U>(value: U): Promise<U> ;
}
class Promise<T> {
new <T> (): Promise <T> ;
inspect(): Promise.PromiseInspection <T> ;
}
export = Promise;
}
Almost there - except that now I'm not allowed to replace class Promise<T> with interface Promise<T>, making Promise<T> unextendable. If I try to do it, the following code:
import Promise = require('bluebird');
var x = new Promise<number>();
x.inspect().value().toExponential();
fails with the error "Invalid 'new' expression"
Link to the actual, work-in-progress bluebird.d.ts - this one currently pollutes the global namespace (uses solution 4)
Is there a better way to do this, or did I hit a language limitation?
Anders Hejlsberg posted an answer on CodePlex, so I'm going to add it here. The declaration merging solution was close - but I also needed a "var" declaration to declare the static interface as it is the only one that can accept a constructor function.
declare module "bluebird" {
module Promise {
export interface PromiseInspection<T> {
value(): T;
}
}
interface Promise<T> {
inspect(): Promise.PromiseInspection <T> ;
}
var Promise: {
new<U>(): Promise<U>;
cast<U>(value: U): Promise<U> ;
}
export = Promise;
}
So basically:
interface members in the module declaration (as long as they declare just types i.e. non-physical)
instance members in the main interface
static function members, the constructor and other "physical" members in the var declaration.
Also, his comment:
Writing it this way you have a separate declaration for each of the three meanings of the identifier Promise: As a namespace (a module containing only types), as a type (that happens to be generic), and as a value.
Looking at your code I noticed you were missing a few export statements. The code below compiles - would it suit?
declare module bluebird {
export class PromiseInspection<T> {
// ...
}
export class Promise<T> {
constructor<T>();
inspect():PromiseInspection<T>;
static all<T>(promises:Promise<T>[]):Promise<T[]>;
}
}
declare module "bluebird" {
export = bluebird;
}
Though I generally favour using interfaces when defining typings as in #2:
declare module bluebird {
export interface PromiseInspection<T> {
// ...
}
export interface Promise<T> {
constructor<T>();
inspect():PromiseInspection<T>;
}
export interface PromiseStatic {
new<T>();
all<T>(promises:Promise<T>[]):Promise<T[]>;
}
}
declare module "bluebird" {
export = bluebird;
}
Failing that have you tried using another promises library as the basis for your typings? You could do worse than look at https://github.com/borisyankov/DefinitelyTyped/blob/master/q/Q.d.ts
Roughly speaking they look a little like this:
declare function Q<T>(promise: Q.IPromise<T>): Q.Promise<T>;
declare function Q<T>(promise: JQueryPromise<T>): Q.Promise<T>;
declare function Q<T>(value: T): Q.Promise<T>;
declare module Q {
//… functions etc in here
}
declare module "q" {
export = Q;
}

TypeScript module and class simultaneously?

I am currently trying to build a TypeScript definition file for OpenLayers.
The problem is that in OpenLayers there are certain classes that would translate to both a module and a class in TypeScript.
For example there is the Protocol class in module OpenLayers and there is a class Response in module OpenLayers.Protocol.
How could I model that in TypeScript? Can I make Protocol a class and define the Response class as a inner class that is exported? How would you go about solving that problem?
Declare Response as a static field of Protocol with a constructor type, returning an interface that defines the Response class:
declare module OpenLayers {
export interface IProtocolResponse {
foo(): void;
}
export class Protocol {
static Response: new () => IProtocolResponse;
}
}
var response = new OpenLayers.Protocol.Response();
response.foo();
Edit:
Or as Anders points out in this discussion list question, you can have multiple constructors for the inner class in this way:
declare module OpenLayers {
export interface IProtocolResponse {
foo(): void;
}
export class Protocol {
static Response: {
new (): IProtocolResponse;
new (string): IProtocolResponse;
};
}
}
var response = new OpenLayers.Protocol.Response('bar');
response.foo();
The main downside of both approaches is that you cannot derive a class from OpenLayers.Protocol.Response.
Here is my updated answer, which I hope helps - it should get you started on defining OpenType:
declare module OpenType {
export class Protocol {
constructor();
Request;
}
}
var x = new OpenType.Protocol();
var y = new x.Request();
var z = x.Request;