Private Type

Topics: General, Language Specification
May 20, 2014 at 3:09 PM
Edited Jun 19, 2014 at 4:36 PM
I'm sorry to insist on that point but it seems that bug: https://typescript.codeplex.com/workitem/1312 has still not make it to the typescript team triage process, and I feel that is an important matter.

In my point of view the impossibility of exporting an object with a signature that involves private type is a serious limitation that prevent us from using a lot of natural javascript patterns/constructions.
In the best cases it forces you to use fundule/clodule where it does not feel very natural :
function myFunction(): myFunction.MyInterface {
  //...
}
module myFunction {
  export interface MyInterface {
    //...
  }
}
export = myFunction;
And in the worst scenario it completely prevents you from modeling your module like you would do it in javascript :
declare function myFactory<T>(): T;

interface MyInterface {
  //...
}

var myObject = myFactory<MyInterface>();
export = myObject; //there is no way to model that correctly
This bug is, for example, responsible of making the usage of Facebook React framework and typescript a painful experience.

Another time I'm sorry to insist where there is already an issue filled, but could we have the point of view of the TypeScript team on that one ?

Regards,
François de Campredon
Jul 2, 2014 at 4:40 PM
bumps ? :p
Developer
Jul 2, 2014 at 7:32 PM
Your issues are being seen, don't worry :) We're still in the process of evaluating what new features we'll be doing for the next version, a lot of our bandwidth is going to be used up on ES6 features but these kinds of things are on our radar, especially as people upvote them.

That said, for this specific issue I see a lot of people noting the problems they have which I definitely understand for certain patterns. On the other hand, what is the actual proposed change? To do away with this type of error entirely? That would cause a great deal of bugs to go uncaught. Certainly open to suggestions if people have a particular design in mind.
Jul 2, 2014 at 8:03 PM
Edited Jul 2, 2014 at 8:04 PM
thank you to reassure me :p.

Honestly I don't really understand why that would be an issue to let exported value use internal type in their type definition, especially for interface, from what I understand :
declare function myFactory<T>(): T;

interface MyInterface {
  prop: string;
}

var myObject = myFactory<MyInterface>();
export = myObject;
and
declare function myFactory<T>(): T;

interface MyInterface {
  prop: string;
}

var myObject = myFactory<{ prop: string; }>();
export = myObject;
is absolutely equivalent, but in the first case the compiler will rise an error.

Even in the case of class :
class MyClass {
 ...
}


var myObject = new MyClass();
export = myObject;
Why would it be harmful ? myObject would be of type MyClass, he would have properties/method of MyClass, why would the fact that MyClass is not directly consumable by an other module would lead to bug ?
Jul 2, 2014 at 8:13 PM
Edited Jul 2, 2014 at 8:15 PM
Seconded. The need to export all accessible classes and types seems completely unnecessary.

It leads to awkward module-interface-var combos to get the proper declaration merging when the module is intended to have a single export.
Coordinator
Jul 2, 2014 at 8:29 PM
Edited Jul 2, 2014 at 8:30 PM
One issue is that non-anonymous types might be infinitely recursive, and we can't represent those anonymously. For example:
/**** Foo.ts ****/
interface SomeType {
    self: SomeType;
}

function fn(n: number): SomeType {
    /* ... */
}

export = fn;

/**** Bar.ts ****/
import foo = require("./Foo");

export var x = foo();
If you run this and want a generated declaration file for Bar.ts, what is the content of Bar.d.ts ?
/**** Bar.d.ts ****/
import foo = require("./Foo");

export var x: { self: { self: { self: { self: { self: { self: { self: { /*... forever ... */ };
This is just the simple case; there are much more complicated cases that are harder to detect.
Jul 2, 2014 at 8:47 PM
Edited Jul 2, 2014 at 9:03 PM
Yeah I guess there is case where that make things harder however that kind of case could be solved by :
  • throwing an error for these specific case
  • use typeof:
 import bar = require("./Bar");
 export var x: { self: typeof bar.x}
  • introduction a keyword that would mark a type as internal for definition file, and allow to reference those internal type only in type annotation something alike :
/**** Foo.d.ts ****/
internal interface SomeType {
 self: SomeType
}

function fn(n: number): SomeType;

export = fn;


/**** Bar.d.ts ****/
import foo = require("./Foo");

export var x:  Foo.internal::SomeType;

  • recreate a named type in declaration file where that type is used
/**** Foo.d.ts ****/
interface SomeType {
 self: SomeType
}

function fn(n: number): SomeType;

export = fn;


/**** Bar.d.ts ****/
interface SomeType {
 self: SomeType
}

export var x:  SomeType;