Implementing TypeScript interface with bare function signature plus other fields - interface

How do I write a class that implements this TypeScript interface (and keeps the TypeScript compiler happy):
interface MyInterface {
(): string;
text2(content: string);
}
I saw this related answer:
How to make a class implement a call signature in Typescript?
But that only works if the interface only has the bare function signature. It doesn't work if you have additional members (such as function text2) to be implemented.

A class cannot implement everything that is available in a typescript interface. Two prime examples are callable signatures and index operations e.g. : Implement an indexible interface
The reason is that an interface is primarily designed to describe anything that JavaScript objects can do. Therefore it needs to be really robust. A TypeScript class however is designed to represent specifically the prototype inheritance in a more OO conventional / easy to understand / easy to type way.
You can still create an object that follows that interface:
interface MyInterface {
(): string;
text2(content: string);
}
var MyType = ((): MyInterface=>{
var x:any = function():string { // Notice the any
return "Some string"; // Dummy implementation
}
x.text2 = function(content:string){
console.log(content); // Dummy implementation
}
return x;
}
);

There's an easy and type-safe way to do this with ES6's Object.assign:
const foo: MyInterface = Object.assign(
// Callable signature implementation
() => 'hi',
{
// Additional properties
text2(content) { /* ... */ }
}
)
Intersection types, which I don't think were available in TypeScript when this question was originally asked and answered, are the secret sauce to getting the typing right.

Here's an elaboration on the accepted answer.
As far as I know, the only way to implement a call-signature is to use a function/method. To implement the remaining members, just define them on this function. This might seem strange to developers coming from C# or Java, but I think it's normal in JavaScript.
In JavaScript, this would be simple because you can just define the function and then add the members. However, TypeScript's type system doesn't allow this because, in this example, Function doesn't define a text2 member.
So to achieve the result you want, you need to bypass the type system while you define the members on the function, and then you can cast the result to the interface type:
//A closure is used here to encapsulate the temporary untyped variable, "result".
var implementation = (() => {
//"any" type specified to bypass type system for next statement.
//Defines the implementation of the call signature.
var result: any = () => "Hello";
//Defines the implementation of the other member.
result.text2 = (content: string) => { };
//Converts the temporary variable to the interface type.
return <MyInterface>result;
})(); //Invokes the closure to produce the implementation
Note that you don't need to use a closure. You could just declare your temporary variable in the same scope as the resulting interface implementation. Another option is to name the closure function to improve readability.
Here's what I think is a more realistic example:
interface TextRetriever {
(): string;
Replace(text: string);
}
function makeInMemoryTextRetriever(initialText: string) {
var currentText = initialText;
var instance: any = () => currentText;
instance.Replace = (newText: string) => currentText = newText;
return <TextRetriever>instance;
}
var inMemoryTextRetriever = makeInMemoryTextRetriever("Hello");

Related

Using Class<T> as a Map key in Haxe

I'd like to store instances of models in a common provider using their classes or interfaces as a keys and then pop them up by class references. I have written some code:
class Provider {
public function new() { }
public function set<T:Any>(instance:T, ?type:Class<T>) {
if (type == null)
type = Type.getClass(instance);
if (type != null && instance != null)
map.set(type, instance);
}
public function get<T:Any>(type:Class<T>):Null<T> {
return cast map.get(type);
}
var map = new Map<Class<Any>, Any>();
}
...alas, it's even doesn't compile.
Probably I have to use qualified class name as a key rather than class/interface reference? But I'd like to keep neat get function design that takes type as argument and returns object just of type taken, without additional type casting.
Is it possible or should I change my approach to this problem?
The issue of using Class<T> as a Map key come up every so often, here is a related discussion. The naive approach of Map<Class<T>, T> fails to compile with something like this:
Abstract haxe.ds.Map has no #:to function that accepts haxe.IMap<Class<Main.T>, Main.T>`
There's several different approaches to this problem:
One can use Type reflection to obtain the fully qualified name of a class instance, and then use that as a key in a Map<String, T>:
var map = new Map<String, Any>();
var name = Type.getClassName(Main);
map[name] = value;
For convenience, you would probably want to have a wrapper that does this for you, such as this ClassMap implementation.
A simpler solution is to simply "trick" Haxe into compiling it by using an empty structure type ({}) as the key type. This causes ObjectMap to be chosen as the underlying map implementation.
var map = new Map<{}, Any>();
map[Main] = value;
However, that allows you to use things as keys that are not of type Class<T>, such as:
map[{foo: "bar"}] = value;
The type safety issues of the previous approach can be remedied by using this ClassKey abstract:
#:coreType abstract ClassKey from Class<Dynamic> to {} {}
This still uses ObjectMap as the underlying map implementation due to the to {} implicit cast. However, using a structure as a key now fails at compile time:
var map = new Map<ClassKey, Any>();
map[{foo: "bar"}] = value; // No #:arrayAccess function accepts arguments [...]

Can I add a method on es6 class after it is defined?

Method
method() {}
function
function func() {}
Above is just to elaborate difference between method and function.
class Student {
constructor(name, age) {
this.name = name;
this.age = age;
}
method1(){}
}
In the above class, after writing the definition.
I want to add a method2 to the class, similar to the way method1 is there.
I can add a function like soo
Student.prototype.func = function(){...}
But I do not have a way to add a method on the same class. and inside function I will not be able to use super as that is just available inside the method.
Is there a way I can add method after the class is defined ?
So that I will be able to use super inside that.
As has already been explained, you can only use super() inside the regular class definition. But, long before we had ES6, we were calling parent method implementations manually. It can be done using the parent's prototype:
class Person {
talk() {
// some implementation here
}
}
class Student extends Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
Student.prototype.talk = function(data) {
// now call base method manually
Person.prototype.talk.call(this, data);
// then do our extra work
log(data);
}
Of course, normally you could just declare all your methods within the class declaration so this would not be something you would normally need to do.
Your snippet adding a new property to the prototype is only approach for adding a function later. One main difference in this case is that simple assignment like that will create the property as enumerable by default, whereas class syntax would create is as non-enumerable. You could use
Object.defineProperty(Student.prototype, "func", {
configurable: true,
writable: true,
value: function() {
},
});
to address that at least.
Unfortunately as you've seen, adding things to the prototype afterward does not allow usage of super.foo. There is no way for this to be supported, because the behavior of super is based specifically on the lexical nesting of the method syntax method(){} being inside of the class syntax. Methods added programmatically later on would have no way to know which prototype is the "super" one.

Class decorator, how to make sure the class is extending and implementing other classes

Sorry for the weird title, I don't quite know how to describe what I'm trying to do in one sentence.
I have to define a bunch of classes that are all going to extend from this one class and also implement this other class.
class SoulCoughing extends Super implements BonBon { /.../ }
class MoveAside extends Super implements BonBon { /.../ }
class LetTheManGoThru extends Super implements BonBon { /.../ }
I have written a sort of wrapper function that I use as a decorator for these classes.
const Eminem = function(klass: Constructable<????>) {
const instance = new klass();
// Do stuff
}
Constructable is a little interface I'm using because otherwise TypeScript would throw an error about not having a constructor.
interface Constructable<T> {
new(): T;
}
Now here is my problem, I don't know what type to assign to parameter klass in my wrapper function? I have tried doing this:
... function(klass: Contrusctable<Super & BonBon>)
and this:
... function(klass: Contrusctable<Super | BonBon>)
I also tried modifying my constructable interface like this:
interface Constructable<T, U> {
new(): T & U;
}
... function(klass: Contrusctable<Super, BonBon>)
but I keep getting an Argument of type 'typeof SoulCoughing' is not assignable to parameter of type 'Constructable<everythingIveTriedSoFar>' error.
So my question is, what type definition should I use with the parameter klass? I know I can just use any but I'd really like to make sure that the class being passed has extended Super and implemented BonBon.
I'm going to guess that the classes SoulCoughing etc. don't actually have no-arg constructors, and therefore cannot act as Constructable<{}> at all; the most likely culprit is that Super's constructor has a mandatory argument, which would make all subclasses fail to match new() by default. Note that this also implies that your implementation of Eminem probably wants to call new klass(...) with some arguments also.
The right way to fix it is to declare Constructable<T> to be a constructor with the right argument types. Let's say Super looks like this:
class Super {
constructor(elevator: number, mezzanine: string) {
//...
}
}
Then you could define Constructable to match:
interface Constructable<T extends Super & BonBon = Super & BonBon> {
new(chump: number, change: string): T; // same args as Super
}
and Eminem like:
const Eminem = function(klass: Constructable) {
const instance = new klass(2, "rise");
// Do stuff
}
and finally:
Eminem(SoulCoughing); // no error
I only kept Constructable generic in case you wanted TypeScript to preserve the type of the particular subclass, like so:
const SlimShady = function <T extends Super & BonBon>(klass: Constructable<T>): T {
return new klass(2, "fat");
}
// returns same type as passed-in constructor
const cutLean: MoveAside = SlimShady(MoveAside);
Okay, hope that helps; good luck!

Class, Interface, Prototype, and else

I'm creating a JavaScript Framework for making applications in the classic Object-Oriented Programming (so with classes/interfaces instead of only prototypes). However I still have a problem with giving names to those.
For instance :
var Bidule = function() { /*...*/ } ;
Bidule.prototype = { /*...*/ } ;
Is Bidule a OOP Class as a class is a constructor ? Or is it only a constructor ?
As classes don't have prototypes, I don't think it could be called a true class.
So it means I should call them both 'Constructors'. However, what about an interface or an abstract class ? What is the correct word if they aren't constructors ? And is an interface a kind of class ?
I've designed constructor functions, classes and interfaces in my Framework. However I need a name to regroup all of theme so we may build one of those like this :
var Bidule = new _NAME_.Class(/*...*/) ; // Where _NAME_ is the name of the container of class/function/interface.
I was thinking of "Concept" but I'm not sure and would like to know your opinions.
I also named "visibility" the common word for describing public/private class,
"type" for static/abstract/interface/singleton/final class. Are those correct ?
And one last question : Is there a difference between the verb 'extend' and 'inherit' ?
Thanks in advance for your answers.
Javascript is not a traditional OO language, it is prototyped. Some concepts about OO cannot be applied to js for this reason.
Bidule is your type, so it is your "class". The constructor is the function you assined to the variable.
var Bidule = function() { /*...*/ } ;
Bidule.prototype = { /*...*/ } ;
var obj = new Bidule();
obj.foo = 'bar';
var obj2 = new Bidule();
obj2.foo = 'foo';
alert(obj instanceof Bidule); // true
alert(obj2 instanceof Bidule); // true
alert(obj.foo); // bar
alert(obj2.foo); // foo
Javascript does not support abstract classes or interfaces and no, interfaces are not some kind of classes. Interfaces defines contracts, or what your class does, but do not specify how.
Extend and inherit have the same meaning in this context.

How to parametrize my exports?

I'd like to be able to parametrize my exports not only with types (as in, generic exports), but also with values.
Something like:
class Greeter
{
readonly string _format;
public Greeter( string format ) { _format = format; }
public string Greet( string name ) { return string.Format( _format, name ); }
}
// ...
var e = new ExportProvider();
e.ExportParametrized<Greeter>( args: new[] { "Hi, {0}!" } );
e.ExportParametrized<Greeter>( args: new[] { "¡Hola, {0}!" } );
// And then:
[ImportMany] IEnumerable<Greeter> Greeters { get; set; }
foreach( var g in Greeters ) Console.WriteLine( g.Greet( "John" ) );
// Should print out:
// Hello, John!
// ¡Hola, John!
One might ask: why don't I simply export the value new Greeter( "Hello, {0}!" ) using ComposablePartExportProvider and CompositionBatch?
While this approach would work in this particular case, it has an important flaw: if the Greeter class had any imports of its own, they would not be satisfied.
The usual way I would go about this is to declare two classes - EnglishGreeter and SpanishGreeter, inherit them both from Greeter, and then provide the appropriate arguments in the call to base constructor.
But this doesn't work for two reasons:
This is a lot of noise to write. Not only do I have to type the whole shebang, I also have to come up with names for those classes, and it doesn't always make sense to have names. Not to mention the DRY principle. But even besides the noise...
Sometimes I don't know the parameters upfront. Say, for example, my greeting formats were coming from some kind of config file.
Here is another thought, to somewhat clarify what I'm looking for.
This problem is almost solved in the TypeCatalog. See, the TypeCatalog knows about the type and it calls the type's constructor to create the part on demand.
One can think of this process from another standpoint: the catalog has a factory function; using that function, it creates the part, then satisfies its non-prerequisite imports, and then returns the part back to the requestor.
Now, in the particular case of TypeCatalog, the factory function just happens to be the type's own constructor. If only I could hook in and replace the factory function with my own, but still leverage the rest of the machinery, that would be exactly what I'm looking for.
You can achieve this by using property exports. You could define a class specifically for those kinds of exports, and it will look like this:
class MyParameterizedExports
{
[Export(typeof(Greeter))]
private Greeter EnglishGreeter
{
get
{
Greeter g = new Greeter("Hi, {0}!");
container.SatisfyImportsOnce(g);
return g;
}
}
[Export(typeof(Greeter))]
private Greeter SpanishGreeter
{
get
{
Greeter g = new Greeter("¡Hola, {0}!");
container.SatisfyImportsOnce(g);
return g;
}
}
}
Here you export two separate Greeter instances without having to define a new class for each type of Greeter.