7

Suppose I have:

class A {
 f():void{}
 g():void{}
}
const a = new A();

type AFunctions = "f" | "g";

I want to iterate AFunctions and produce new functions. Similar to mapped types but with implementation and without manually writing all keys of course.

Pseudo code

const b: A = {
 for F in AFunctions add function F() {
   return a[f]();
  }
}
2
  • Do the new functions have the same signature as in A ? Or do they at least have the same signature signature between them ? Commented Feb 6, 2018 at 14:32
  • For simplicity they all have same signature () => void. Commented Feb 6, 2018 at 15:14

1 Answer 1

3

You can iterate the properties of the class using Object.getOwnPropertyNames and Object.getPrototypeOf.

function mapFunctions<T>(type: new (... params: any[])=> T) : { [P in keyof T] : ()=> void } {
    let mapped: { [name: string] : ()=> void } = {}

    let p = type.prototype;
    while(p !=  Object.prototype) {
        for (const prop of Object.getOwnPropertyNames(p)) {
            if(prop == 'constructor') continue;
            if(typeof p[prop] !== 'function') continue;

            mapped[prop] = ()=> {
                console.log(prop);
            }
        }
        p = Object.getPrototypeOf(p);
    }

    return <any>mapped;
}
class A {
    f(): void { }
    g(): void { }
}

class B extends A{
    h(): void { }
    i(): void { }
}
let ss = mapFunctions(B); // has functions f,g,h,i

Tying the type of the function to the result of the function on the origin object is more difficult, Conditional types and their associated inference behavior in 2.8 will let you drill down to return type and argument types, but for now you could only use the full function type, such as { [P in keyof T] : ()=> T[P] } (for a function with no parameters that return a function with the same signature as the original) or { [P in keyof T] : (fn: T[P])=> void } (for a function that takes a function with the same signature as the original as a parameter)

Sign up to request clarification or add additional context in comments.

7 Comments

Iterating over prototype is not bad 'let p = type.prototype;' , but I want a compile time simple solution. The compiler has the all data I need, it just needs to be exposed.
@NN_ I agree the compiler has all the info, it's just that it doesn't want to hand it over. I don't think there is a way force the compiler to give you the values for the names.
There is TS transformers which allows to generate such code. See: github.com/kimamula/ts-transformer-keys
@NN_ Well, if you are willing to roll out your own custom compiler sky's the limit in terms of what you can do :)
Transformer is part of compiler API. You don't invent a new compiler. Btw here is the answer: github.com/kimamula/ts-transformer-keys/issues/15
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.