12

I have some typescript code, and I'm doing some metaprogramming where I need to be able to access instance.func.name, however TypeScript omits the function name in the compiled JS.

TypeScript:

class ClassName {
    // ... 
    func(): ReturnType {
        // ...
    }
}

Compiled JavaScript:

// ...
ClassName.prototype.func = function () {
    // ... 
};

Desired JavaScript:

ClassName.prototype.func = function func() {
    // ...                          ^^^^
};

Is there a compiler option I'm missing, or a keyword I can use in TypeScript to accomplish this?

2 Answers 2

14

A solution, once which I will not be marking as accepted, because it doesn't provide the name property, but does work with any other identifier is as follows:

function named(target: any, key: string) {
    target[key].functionName = key;
}

class ClassName {
    // ... 
    @named
    func(): ReturnType {
         // ...
    }
}

Then access instance.func.functionName.

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

1 Comment

pretty clever solution
7

It is not possible to use TypeScript decorators because function.name is readonly property.

There is a hacky way:

class ClassName {
    // ... 
    public func = function test() {

    }

    public func2() {

    }
}

let instance = new ClassName();

console.log("RESULT", instance.func['name']);

but it is not exactly what you ask for (i.e. notice the missing prototype in the function declaration).

Edit: TypeScript compiler does not write the function name because there is no handling for SyntaxKind.MethodDeclaration in emitter.ts:

function shouldEmitFunctionName(node: FunctionLikeDeclaration) {
    if (node.kind === SyntaxKind.FunctionExpression) {
        // Emit name if one is present
        return !!node.name;
    }
    if (node.kind === SyntaxKind.FunctionDeclaration) {
        // Emit name if one is present, or emit generated name in down-level case (for export default case)
        return !!node.name || languageVersion < ScriptTarget.ES6;
    }
}

If you want to get your hands dirty, then you can update ./node_modules/typescript/lib/typescript.js file. Just add the last condition:

function shouldEmitFunctionName(node) {
    if (node.kind === 173 /* FunctionExpression */) {
        // Emit name if one is present
        return !!node.name;
    }
    if (node.kind === 213 /* FunctionDeclaration */) {
        // Emit name if one is present, or emit generated name in down-level case (for export default case)
        return !!node.name || languageVersion < 2 /* ES6 */;
    }

    // MODIFIED
    if (node.kind === 143 /* MethodDeclaration */) {                    
        return true;
    }                                                        
}

and run this to test the change:

$ node ./node_modules/typescript/lib/typescript.js hello.ts

4 Comments

Yeah, close but not quite (missing proto). Didn't know TypeScript supported what looks like ES2016 properties though. Handy.
Nice find, have an upvote. I need to still to stock TypeScript for this project though. :(
Ask this question here github.com/Microsoft/TypeScript/issues. You can link this question, so that they won't need to start from scratch. You will have a definite answer then and act accordingly.
Done. Will the answer be definitely typed? (I apologize profusely for that joke)

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.