Repository navigation
How to handle this when this is a function #22285
Description
Activity
- ghost addedNeeds More InfoThe issue still hasn't been fully clarifiedThe issue still hasn't been fully clarified
on Mar 2, 2018 Ok so here is a jsfiddle of plain js and here is the code:
function extend(Class) { const name = Class.name; const symbol = Symbol(name); // callable `this` in `Adder#add` Class.for = function _for(value) { return value[symbol]; } Class.instance = function(constructor, methods) { constructor.prototype[symbol] = methods; } Class.symbol = symbol; const properties = Object.getOwnPropertyDescriptors(Class.prototype); Object.keys(properties) .filter(key => key !== 'constructor') .forEach(key => { // bind `for` so `this(a)` calls `Class.for` Class.prototype[key] = Class.prototype[key].bind(Class.for) }); return Class } const Adder = extend( class Adder { add(left, right) { const { add } = this(left); return add(left, right); } } ) const { add } = Adder.prototype; Adder.instance(Number, { add(left, right) { return left + right; } }); console.log(add(1, 2)); // 3 Adder.instance(String, { add(left, right) { return left.concat(right); } }); console.log(add("1", "2")); // "12"Class.foris what is is what gets called viathisin this codeconst { add } = this(left);This will return the correct
adddependant if it is aStringor aNumber.This is the code that makes
thisan alias toClass.forObject.keys(properties) .filter(key => key !== 'constructor') .forEach(key => { // bind for so `this()` calls `Class.for` Class.prototype[key] = Class.prototype[key].bind(Class.for) });So back to the typescript example:
it would be:
export interface Adder<A> { add(left: A, right: A) => A; } const Adder = extend( class Adder<A> { add(this: (a: A) => Adder<A>, left: A, right: A): A { const {add} = this(left); // will call Class.for for the specific implementation return add(left, right); } } ); export { add } = Adder.prototype;So is this too exotic for typescript to recognise or can I somehow indicate that the
thisin{ add }has this bound by the call in extend with the lineClass.prototype[key] = Class.prototype[key].bind(Class.for)This is really great but one thing, typescript does currently not support a symbol as an indexer:
So the only way is to give the member
anyas its typeexport class TypeClass<A> { readonly symbol: any;Or is there another way?
Andy (Andrewkraft) (@Andy-MS) this has been extremely helpful. I'm going to close the issue but is it possible to explain this commented line:
instance<J extends T>(type: Function, implementation: J) { type.prototype[this.symbol] = implementation; }Why is it not just T that is the generic argument?
Andy (Andrewkraft) (@Andy-MS) one problem with this is approach is that it expects the first argument to be the type argument, i.e.
return ((left: any, ...args: any[]) => { const impl = left[this.symbol] as T;but what if the type in question is not the first argument in question. Generic types do not exist at runtime in typescript as I've no idea what that would compile to.
I guess I would need to pass something into the
instancefunction to indicate what where to get the type from?- locked and limited conversation to collaborators
on Jul 25, 2018
I have created this playground that shows the problem.
The code looks like this:
How do I handle
thison line 44 of the playgroundlet { doSomething } = this(left);the call to
thiswill return the specificdoSomething.At the moment I get the error, this lacks a callable signature.
If I add the false this param like this:
doSomething(this: (a: A) => Implementation<A>, left: A, right: A) {And if I then export the function
export {doSomething} = Implementation.prototype;And I then try to use the function:
doSomething({o: 1}, {b: 2});I get the error:I realise this is quite contrived but is this too contrived for typescript?