Best explained with an example:
some-class.js
function SomeClass() { /* ... */ }
SomeClass.prototype.doSomething = function() { /* ... */ };
export function createSomeClass() {
return new SomeClass();
}
index.js
import { createSomeClass } from './some-class';
/**
* #param {SomeClass} someClass
*/
function foo(someClass) {
someClass.doSomething();
}
var someClass = createSomeClass();
someClass.doSomething();
This code leads to errors in VSCodes TypeScript checker and won't provide code completion for the class inside foo:
An alternative would be to export the class constructor and import it in index.js which gives me full code completion but adds a warning due to the unused import of the class:
What I also don't like about this solution is that it "leaks" the class to the outside which is not necessary otherwise due to the createSomeClass factory.
Is there some way to have full annotations & code completion without the unused import of the class?
Related
I have created a default class file for handling the xpath under default package,
public class TestObjectHelper {
/*
* TestObjectHelper will help the user to handle dynamic xpath
*/
public static TestObject getTestObjectWithXpath(String xpath) {
return new TestObject().addProperty('xpath', ConditionType.EQUALS, xpath)
}
}
I want to use it another package, but it is not identifying the above method.
import statement
You need to call the function the following,
import TestObjectHelper
or suggest to move this under a separate package let's call it as com.utilites
import com.utilites.TestObjectHelper
I have this namespace
namespace Validation {
export function Func1() {
// code
}
export function Func2() {
// code
}
}
Which I can import in my app.ts:
import Validations = Validation;
But when I want to reference some modules in my Validation namespace
import {Request, Response} from 'express';
var jwt = require('jsonwebtoken');
var express = require('express');
import {Config} from './../config';
namespace Validation {
export function Func1() {
// code
}
export function Func2() {
// code
}
}
So then import Validations = Validation; in my app.ts giving me an error cannot find namespace Validation.
Why it is happened? Any thoughts how to fix?
UPDATE 1 : In case if I put imports after namespace I am getting an error Import declaration in a namespace cannot import a module:
namespace Validation {
import {Request, Response} from 'express'; //Error: Import declaration in a namespace cannot import a module
var jwt = require('jsonwebtoken');
var express = require('express');
import {Config} from './../config'; //Error: Import declaration in a namespace cannot import a module
export function Func1() {
// code
}
export function Func2() {
// code
}
}
my config.ts is just a simple class:
export class Config {
public static get Secret():string { return 'stuff'; }
public static get Database():string { return 'mongodb://127.0.0.1:27019/test'; }
}
And 'express' it is an npm package
UPDATE 2
I think I just fixed config by wrapping it in to namespace:
namespace Common {
export class Config { .. }
}
Also changed import statement from this import {Config} from './config'; to this: import Config = Common.Config; but haven't yet figure out how to fix 'express' thing
This happens because from the moment you put a top-level import or export statement into a file, that file is treated as an external module itself. If you are using internal modules (namespaces), I suggest importing inside namespaces, so that there are no top-level import or export statements.
namespace Validation {
import Request = ...;
import Response = ...;
export function Func1() {
// code
}
export function Func2() {
// code
}
}
The other approach would be to use external modules instead, but that requires a module loading system, which might be superfluous in many cases.
Right now, you are mixing internal and external modules, which is not recommended. Regarding complex structural cases like this, Typescript is still very far from being a mature language.
I assume that you have defined your validation functions in the separate (from app.ts) file. If this is the case then what you need to do is:
In your Validation.ts:
export function Func1() {
// code
}
export function Func2() {
// code
}
In your app.ts:
import * as Validation from './Validation';
Validation.Func1();
Your problem is most likely in mixing together concepts of modules and namespaces in typescript. Have a look here: Namespaces and Modules, and be sure to look through Modules and Namespaces
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() { /* ... */ }
}
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;
}
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