lomas09
lomas09

Reputation: 1104

Typescript: Calling Method from within Method Parameters

I guess this is more of a curiosity question, and it would be nice if it can actually be implemented in typescript.

Basically I have a class and two methods inside it like so:

Is this possible?


class MyClass{
   private cleanup(str:String):String{
     //clean up the string
     return str; //return sanitized string
   }
   //I want to do this
   insertString(this.cleanup(text_1:String), this.cleanup(text_2:String)){
     console.log(text_1 + text_2);
   }
}

Instead of this?


class MyClass{
   private cleanup(str:String):String{
     //clean up the string
     return str; //return sanitized string
   }
   //might get to long if I have to cleanup to many strings
   insertString(text_1:String, text_2:String){
     text_1 = this.cleanup(text_1)
     text_2 = this.cleanup(text_2)
     console.log(text_1 + text_2);
   }
}

Upvotes: 3

Views: 2764

Answers (1)

zlumer
zlumer

Reputation: 7004

What you're trying to achieve is not actually calling a method from another method signature. It's more about processing your list of arguments.

1: arguments hack

You can modify the provided arguments array and the corresponding named parameters will also change.

insertString(text_1:String, text_2:String) {
    // here text_1 and text_2 are not cleaned up yet
    for (var i = 0; i < arguments.length; i++) {
        arguments[i] = this.cleanup(arguments[i])
    }
    // text_1 and text_2 are now cleaned up
}

However, this approach is hackish, and you can go with #2:

2: Decorators

We declare two decorators: one parameter decorator named cleanup:

function cleanup(target: Object, propertyKey: string | symbol, parameterIndex: number) {
    let cleanupParams: number[] = Reflect.getOwnMetadata("MyClass:cleanup", target, propertyKey) || [];
    cleanupParams.push(parameterIndex);
    Reflect.defineMetadata("MyClass:cleanup", cleanupParams, target, propertyKey);
}

And one method decorator named CleanupMethod (it's actually a decorator factory):

function CleanupMethod(func){
    return function (target: any, propertyName: string, descriptor: TypedPropertyDescriptor<Function>) {
        let method = descriptor.value;
        descriptor.value = function () {
            let requiredParameters: number[] = Reflect.getOwnMetadata("MyClass:cleanup", target, propertyName);
            if (requiredParameters) {
                for (let parameterIndex of requiredParameters) {
                    arguments[parameterIndex] = func(arguments[parameterIndex]);
                }
            }
            return method.apply(this, arguments);
        }
    }
}

In the decorators we save a list of which parameters should be sanitized on function enter and then on every call we sanitize them.

Usage:

class MyClass{
    private cleanup(str:string):string{
        //clean up the string
        return '[sanitized ' + str + ']'; //return sanitized string
    }
    @CleanupMethod(MyClass.prototype.cleanup)
    insertString(text_1:string, @cleanup text_2:string){
        console.log(text_1 + text_2);
    }
    @CleanupMethod(MyClass.prototype.cleanup)
    insertNumber(n1: number, n2: number, @cleanup n3: number, n4: number, n5: number){
        console.log(`${n1} + ${n2} + ${n3} + ${n4} + ${n5}`)
    }
}
var m = new MyClass();
m.insertString('a', 'b') // outputs `a[sanitized b]`
m.insertNumber(10,20,30,40,50) // outputs `10 + 20 + [sanitized 30] + 40 + 50`

Cleanup function is passed as a parameter to CleanupMethod factory. That way you can have different cleanup functions, e.g.:

@CleanupMethod(cleanupString)
insertString( @cleanup str1: string, @cleanup str2: string2 ){
    /*...*/
}
@CleanupMethod(cleanupNumber)
insertNumber( @cleanup n1: number ){
    /*...*/
}

If you want, you can rewrite the decorator code and move cleanup function to parameter decorator, but that will increase the amount of code needed:

@CleanupMethod
insertString( @cleanup(cleanupString) str1: string, @cleanup(cleanupNumber) n1: number ){
    /*...*/
}

More on decorators

Upvotes: 3

Related Questions