3

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);
   }
}

2
  • This insertString(this.cleanup(text_1:String), this.cleanup(text_2:String)) is not a function declaration, so it will not be possible. A function declaration contains the number of arguments and their types. If you want to do something with the arguments it will have to be done in the function body. Commented Jun 23, 2016 at 15:51
  • @Tomalak not even using something like insertString(text_1:String = this.cleanup(text_1), text_2:String = this.cleanup(text_2)) or some kind of arrow function-like kind of syntax? Commented Jun 23, 2016 at 15:58

1 Answer 1

3

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

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

1 Comment

great answer! This is beyond the scope of what I intended to do but it is still helpful and insightful.

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.