Para quem está interessado em estilo funcional ou procura uma abordagem mais expressiva para utilizar em metaprogramação (como verificação de tipo), pode ser interessante ver a biblioteca Ramda para realizar essa tarefa.
O código seguinte contém apenas funções puras e sem ponto:
const R = require('ramda');
const isPrototypeEquals = R.pipe(Object.getPrototypeOf, R.equals);
const equalsSyncFunction = isPrototypeEquals(() => {});
const isSyncFunction = R.pipe(Object.getPrototypeOf, equalsSyncFunction);
No ES2017, as async
funções estão disponíveis, para que possamos verificar também:
const equalsAsyncFunction = isPrototypeEquals(async () => {});
const isAsyncFunction = R.pipe(Object.getPrototypeOf, equalsAsyncFunction);
E depois combine-os:
const isFunction = R.either(isSyncFunction, isAsyncFunction);
Obviamente, a função deve ser protegida contra null
e undefined
valores, para torná-la "segura":
const safeIsFunction = R.unless(R.isNil, isFunction);
E, complete o snippet para resumir:
const R = require('ramda');
const isPrototypeEquals = R.pipe(Object.getPrototypeOf, R.equals);
const equalsSyncFunction = isPrototypeEquals(() => {});
const equalsAsyncFunction = isPrototypeEquals(async () => {});
const isSyncFunction = R.pipe(Object.getPrototypeOf, equalsSyncFunction);
const isAsyncFunction = R.pipe(Object.getPrototypeOf, equalsAsyncFunction);
const isFunction = R.either(isSyncFunction, isAsyncFunction);
const safeIsFunction = R.unless(R.isNil, isFunction);
// ---
console.log(safeIsFunction( function () {} ));
console.log(safeIsFunction( () => {} ));
console.log(safeIsFunction( (async () => {}) ));
console.log(safeIsFunction( new class {} ));
console.log(safeIsFunction( {} ));
console.log(safeIsFunction( [] ));
console.log(safeIsFunction( 'a' ));
console.log(safeIsFunction( 1 ));
console.log(safeIsFunction( null ));
console.log(safeIsFunction( undefined ));
No entanto, observe que esta solução pode mostrar menos desempenho do que outras opções disponíveis devido ao uso extensivo de funções de ordem superior.