Get Functions (Methods) of a Class

Get functions (methods) of a class

This function will get all functions. Inherited or not, enumerable or not. All functions are included.

function getAllFuncs(toCheck) {
const props = [];
let obj = toCheck;
do {
props.push(...Object.getOwnPropertyNames(obj));
} while (obj = Object.getPrototypeOf(obj));

return props.sort().filter((e, i, arr) => {
if (e!=arr[i+1] && typeof toCheck[e] == 'function') return true;
});
}

Do test

getAllFuncs([1,3]);

console output:

["constructor", "toString", "toLocaleString", "join", "pop", "push", "concat", "reverse", "shift", "unshift", "slice", "splice", "sort", "filter", "forEach", "some", "every", "map", "indexOf", "lastIndexOf", "reduce", "reduceRight", "entries", "keys", "constructor", "toString", "toLocaleString", "valueOf", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", "__defineGetter__", "__lookupGetter__", "__defineSetter__", "__lookupSetter__"]

Note

It doesn't return functions defined via symbols;

How do I get list of methods in a Python class?

An example (listing the methods of the optparse.OptionParser class):

>>> from optparse import OptionParser
>>> import inspect
#python2
>>> inspect.getmembers(OptionParser, predicate=inspect.ismethod)
[([('__init__', <unbound method OptionParser.__init__>),
...
('add_option', <unbound method OptionParser.add_option>),
('add_option_group', <unbound method OptionParser.add_option_group>),
('add_options', <unbound method OptionParser.add_options>),
('check_values', <unbound method OptionParser.check_values>),
('destroy', <unbound method OptionParser.destroy>),
('disable_interspersed_args',
<unbound method OptionParser.disable_interspersed_args>),
('enable_interspersed_args',
<unbound method OptionParser.enable_interspersed_args>),
('error', <unbound method OptionParser.error>),
('exit', <unbound method OptionParser.exit>),
('expand_prog_name', <unbound method OptionParser.expand_prog_name>),
...
]
# python3
>>> inspect.getmembers(OptionParser, predicate=inspect.isfunction)
...

Notice that getmembers returns a list of 2-tuples. The first item is the name of the member, the second item is the value.

You can also pass an instance to getmembers:

>>> parser = OptionParser()
>>> inspect.getmembers(parser, predicate=inspect.ismethod)
...

How to get all functions of es6 class instance

You have to call Object.getOwnPropertyNames() on the prototype property of the class.

class Test {  methodA() {}  methodB() {}}
console.log(Object.getOwnPropertyNames(Test.prototype))

Get class methods in typescript

You forget that TypeScript is Javascript. Remember that the TypeScript compiler compiles your code into Javascript.

So, as you normally do in Javascript, you can enumerate members on an object like this:

UtilityClass myclass = ...;

for (var member in myclass) { /* do something */ }

More advanced

If you want to make sure you don't get inherited members:

for (var member in myclass) {
if (myclass.hasOwnProperty(member)) {
/* do something */
}
}

Extract methods

If you want to make sure you get only methods (functions):

for (var member in myclass) { // For each member of the dictionary
if (typeof myclass[member] == "function") { // Is it a function?
if (myclass.hasOwnProperty(member)) { // Not inherited
// do something...
}
}
}

Reflection in TypeScript

As you can see the approaches require an instance to work on. You don't work on the class. Reflection is what you are trying to achieve in the context of OOP; however Javascript (which is not OOP) deals with it in a different way.

Getting all class methods in classes in current file in Python?

On Python 3, calling inspect.ismethod on an attribute of a class that happens to be a function will always be False, because it will just be a plain function. function.__get__ only returns a method object when accessed as an attribute of an instance.

If you want to get all "methods" of the class just use inspect.isfunction.

>>> class A:
... def __init__(self): pass
...
>>> A.__init__
<function A.__init__ at 0x7fd524dd2f80>
>>> inspect.ismethod(A.__init__)
False
>>> inspect.isfunction(A.__init__)
True
>>> inspect.ismethod(A().__init__)
True

Get methods of class in JavaScript

You can use Object.getOwnPropertyNames and filter the instance and static methods:

class c {  methodA(){}  static methodB(){}
log(){console.log(/*methods*/);} static logStatic(){console.log(/*static methods*/)}}const instanceOnly = Object.getOwnPropertyNames(c.prototype) .filter(prop => prop != "constructor");console.log(instanceOnly);const staticOnly = Object.getOwnPropertyNames(c) .filter(prop => typeof c[prop] === "function");console.log(staticOnly);

Get return type of class method via method name in Typescript

Afaik ,there is no safe way to do what you want without changing function body or using type assertion.

In order to validate function arguments, first of all we need to obtain all method keys from Foo:

class Foo {
var1: string = 'var1';
var2: string = 'var2';

hello(request: string) { }

world(request: number) { }
}

// This type reflects any function/method
type Fn = (...args: any[]) => any

type ObtainMethods<T> = {
[Prop in keyof T]: T[Prop] extends Fn ? Prop : never
}[keyof T]

// "hello" | "world"
type AllowedMethods = ObtainMethods<Foo>

Let's test it:


const executeFoo = <Method extends ObtainMethods<Foo>>(
methodName: Method
) => { }

executeFoo('hello') // ok
executeFoo('world') // ok
executeFoo('var1') // expected error

However, there is a problem with second argument:

const executeFoo = <Method extends ObtainMethods<Foo>>(
methodName: Method, parameter: Parameters<Foo[Method]>[0]
) => {
// Argument of type 'string | number' is not assignable to parameter of type 'never'. Type 'string' is not assignable to type 'never'.
foo[methodName](parameter)
}

As you might have noticed, there is an error.

Argument of type 'string | number' is not assignable to parameter of type 'never'. 
Type 'string' is not assignable to type 'never'.

It is very important. If you try to call foo[methodName]() you will see that this function expects never as a type for first argument. This is because

Likewise, multiple candidates for the same type variable in contra-variant positions causes an intersection type to be inferred.

You can find more in my article, in the first part. This is because TS does not know which methodName you are using exactly. Hence, TS compiler intersects all parameters from methods: string & number because this is the only safe way to make function signature safe.

SO, it is very important what type of argument are you expect in your methods.

How to fix it ?

In this particular example, I believe using type assertion is justified:


const executeFoo = <Method extends ObtainMethods<Foo>>(
methodName: Method, parameter: Parameters<Foo[Method]>[0]
) => {
(foo[methodName] as (arg: Parameters<Foo[Method]>[0]) => void)(parameter)
}

executeFoo('hello', 'str') // ok
executeFoo('world', 42) // ok
executeFoo('world', "42") // expected error
executeFoo('var1') // expected error

Playground

If you are interested in function argument inference you can check my blog

It is also possible to use conditional statement for type narrowing (works in TS >= 4.6)

type Fn = (...args: any[]) => any

type ObtainMethods<T> = {
[Prop in keyof T]: T[Prop] extends Fn ? Prop : never
}[keyof T]

// "hello" | "world"
type AllowedMethods = ObtainMethods<Foo>

type Values<T> = T[keyof T]

type AllowedArguments = {
[Method in AllowedMethods]: [Method, Parameters<Foo[Method]>[0]]
}

const foo = new Foo();

const executeFoo = (
...[name, arg]: Values<AllowedArguments>
) => {
if (name === 'hello') {
foo[name](arg)
} else {
foo[name](arg)
}
}

executeFoo('hello', 'str') // ok
executeFoo('world', 42) // ok
executeFoo('world', "42") // expected error
executeFoo('var1') // expected error

but it does not make much sense.

Can I get all methods of a class?

To know about all methods use this statement in console:

javap -cp jar-file.jar packagename.classname

or

javap class-file.class packagename.classname

or for example:

javap java.lang.StringBuffer

Get function reference of class (not object)

The methods defined with method syntax in the body of a class construct that aren't marked static are prototype methods and so they're on Temp.prototype, not Temp itself. So that's where you'd update them:

Temp.prototype.hi = modifyMethod(Temp.prototype.hi);

Only static methods end up on Temp itself.

You may see other functions created within the class body using the class fields proposal's syntax:

class Temp {
hi = () => {
//
};
}

Those are instance methods. They're created by the constructor, and re-created for each instance, roughly as though they'd been written like this:¹

class Temp {
constructor() {
this.hi = () => {
//
};
}
}

You can't wrap those until/unless an instance is created, as they're instance-specific.

So to wrap up, consider:

class Temp {
static staticMethod() {
// ...
}
prototypeMethod() {
// ...
}
instanceMethod = () => {
// ...
};
constructor() {
this.anotherInstanceMethod = () => {
// ...
};
this.yetAnotherInstanceMethod = function {
// ...
};
}
}

That class shows the three types of methods:

  • Static Methods, such as staticMethod, which you'll find on Temp (e.g., Temp.staticMethod);
  • Prototype Methods, such as prototypeMethod, which you'll find on Temp.prototype (e.g., Temp.prototype.prototypeMethod); and
  • Instance Methods, such as instanceMethod, anotherInstanceMethod, and yetAnotherInstanceMethod, which you'll find on the instances themselves, if/when any instances are created

¹ Technically, they're created as though with Object.defineProperty like this:

class Temp {
constructor() {
Object.defineProperty(this, "hi", {
value: () => {
//
},
writable: true,
configurable: true,
enumerable: true
});
}
}

...not via simple assignment. I used simple assignment in the example to keep it...simple. :-)



Related Topics



Leave a reply



Submit