isFunction
檢查值是否為函數類型。
基礎用法
typescript
import { isFunction } from 'radash'
console.log(isFunction(() => {})) // true
console.log(isFunction(function() {})) // true
console.log(isFunction(async () => {})) // true
console.log(isFunction('hello')) // false
console.log(isFunction(123)) // false
console.log(isFunction({})) // false
語法
typescript
function isFunction(value: any): value is Function
參數
value
(any): 要檢查的值
返回值
返回一個布爾值,如果值是函數則返回 true
,否則返回 false
。同時作為TypeScript類型守衛。
示例
基本類型檢查
typescript
import { isFunction } from 'radash'
// 函數類型
console.log(isFunction(() => {})) // true
console.log(isFunction(function() {})) // true
console.log(isFunction(async () => {})) // true
console.log(isFunction(function*() {})) // true
console.log(isFunction(() => 'hello')) // true
// 非函數類型
console.log(isFunction('hello')) // false
console.log(isFunction(123)) // false
console.log(isFunction(true)) // false
console.log(isFunction(null)) // false
console.log(isFunction(undefined)) // false
console.log(isFunction([])) // false
console.log(isFunction({})) // false
不同類型函數檢查
typescript
import { isFunction } from 'radash'
// 箭頭函數
const arrowFunc = () => 'hello'
console.log(isFunction(arrowFunc)) // true
// 普通函數
function normalFunc() { return 'hello' }
console.log(isFunction(normalFunc)) // true
// 異步函數
async function asyncFunc() { return 'hello' }
console.log(isFunction(asyncFunc)) // true
// 生成器函數
function* generatorFunc() { yield 'hello' }
console.log(isFunction(generatorFunc)) // true
// 構造函數
function Constructor() { this.name = 'test' }
console.log(isFunction(Constructor)) // true
// 類構造函數
class MyClass {}
console.log(isFunction(MyClass)) // true
類型守衛使用
typescript
import { isFunction } from 'radash'
function processValue(value: unknown) {
if (isFunction(value)) {
// TypeScript 知道 value 是函數
console.log('Processing function:', value.name || 'anonymous')
return value()
}
console.log('Not a function')
return null
}
console.log(processValue(() => 'hello')) // Processing function: anonymous hello
console.log(processValue('not a function')) // Not a function null
數組過濾
typescript
import { isFunction } from 'radash'
const mixedArray = [
() => 'hello',
'string',
123,
function() { return 'world' },
async () => 'async',
{},
[]
]
const functions = mixedArray.filter(isFunction)
console.log(functions.length) // 3
const nonFunctions = mixedArray.filter(item => !isFunction(item))
console.log(nonFunctions.length) // 4
對象屬性檢查
typescript
import { isFunction } from 'radash'
const obj = {
name: 'Alice',
age: 25,
greet: () => 'Hello!',
calculate: function(a: number, b: number) { return a + b },
async fetchData() { return 'data' },
isActive: true
}
const functionProperties = Object.entries(obj)
.filter(([key, value]) => isFunction(value))
.map(([key, value]) => ({ key, type: value.constructor.name }))
console.log(functionProperties)
// [
// { key: 'greet', type: 'Function' },
// { key: 'calculate', type: 'Function' },
// { key: 'fetchData', type: 'AsyncFunction' }
// ]
事件處理器檢查
typescript
import { isFunction } from 'radash'
const eventHandlers = {
onClick: () => console.log('clicked'),
onSubmit: function(data: any) { console.log('submitted', data) },
onError: null,
onLoad: undefined,
onResize: 'not a function'
}
const validHandlers = Object.entries(eventHandlers)
.filter(([key, value]) => isFunction(value))
.reduce((acc, [key, value]) => {
acc[key] = value
return acc
}, {} as Record<string, Function>)
console.log(Object.keys(validHandlers)) // ['onClick', 'onSubmit']
API響應處理
typescript
import { isFunction } from 'radash'
interface ApiResponse {
data: unknown
handlers: Record<string, unknown>
callbacks: unknown[]
}
function processApiResponse(response: ApiResponse) {
const validHandlers = Object.entries(response.handlers)
.filter(([key, value]) => isFunction(value))
.reduce((acc, [key, value]) => {
acc[key] = value as Function
return acc
}, {} as Record<string, Function>)
const validCallbacks = response.callbacks.filter(isFunction)
return {
data: response.data,
validHandlers,
validCallbacks
}
}
const response: ApiResponse = {
data: { id: 1, name: 'Alice' },
handlers: {
success: (data: any) => console.log('Success:', data),
error: 'not a function',
complete: () => console.log('Complete')
},
callbacks: [
() => 'callback1',
'not a function',
() => 'callback2'
]
}
const processed = processApiResponse(response)
console.log(Object.keys(processed.validHandlers)) // ['success', 'complete']
console.log(processed.validCallbacks.length) // 2
插件系統
typescript
import { isFunction } from 'radash'
interface Plugin {
name: string
init?: Function
destroy?: Function
render?: Function
}
function validatePlugin(plugin: unknown): plugin is Plugin {
if (typeof plugin !== 'object' || plugin === null) return false
const p = plugin as any
if (typeof p.name !== 'string') return false
if (p.init !== undefined && !isFunction(p.init)) return false
if (p.destroy !== undefined && !isFunction(p.destroy)) return false
if (p.render !== undefined && !isFunction(p.render)) return false
return true
}
const validPlugin: Plugin = {
name: 'MyPlugin',
init: () => console.log('Plugin initialized'),
render: () => '<div>Plugin content</div>'
}
const invalidPlugin = {
name: 'InvalidPlugin',
init: 'not a function'
}
console.log(validatePlugin(validPlugin)) // true
console.log(validatePlugin(invalidPlugin)) // false
中間件系統
typescript
import { isFunction } from 'radash'
type Middleware = (req: any, res: any, next: Function) => void
function validateMiddleware(middleware: unknown): middleware is Middleware {
return isFunction(middleware) && middleware.length >= 2
}
const validMiddleware: Middleware = (req, res, next) => {
console.log('Processing request')
next()
}
const invalidMiddleware = 'not a function'
const middlewareArray = [
validMiddleware,
invalidMiddleware,
(req: any, res: any) => console.log('No next parameter'),
(req: any) => console.log('Missing parameters')
]
const validMiddlewares = middlewareArray.filter(validateMiddleware)
console.log(validMiddlewares.length) // 1
配置驗證
typescript
import { isFunction } from 'radash'
interface Config {
port: number
host: string
handlers: Record<string, unknown>
validators: unknown[]
}
function validateConfig(config: Config) {
const errors: string[] = []
// 驗證處理器
Object.entries(config.handlers).forEach(([key, value]) => {
if (!isFunction(value)) {
errors.push(`Handler '${key}' must be a function`)
}
})
// 驗證驗證器
config.validators.forEach((validator, index) => {
if (!isFunction(validator)) {
errors.push(`Validator at index ${index} must be a function`)
}
})
return errors
}
const config: Config = {
port: 3000,
host: 'localhost',
handlers: {
onRequest: (req: any) => console.log(req),
onResponse: 'not a function',
onError: () => console.log('Error')
},
validators: [
(data: any) => data.id > 0,
'not a function',
(data: any) => data.name.length > 0
]
}
console.log(validateConfig(config))
// ['Handler \'onResponse\' must be a function', 'Validator at index 1 must be a function']
回調函數處理
typescript
import { isFunction } from 'radash'
function executeCallback(callback: unknown, ...args: any[]) {
if (!isFunction(callback)) {
console.warn('Callback is not a function')
return
}
try {
return callback(...args)
} catch (error) {
console.error('Callback execution failed:', error)
}
}
// 有效回調
executeCallback((name: string) => `Hello ${name}!`, 'Alice')
// 輸出: Hello Alice!
// 無效回調
executeCallback('not a function', 'Alice')
// 輸出: Callback is not a function
事件系統
typescript
import { isFunction } from 'radash'
class EventEmitter {
private events: Record<string, Function[]> = {}
on(event: string, listener: unknown) {
if (!isFunction(listener)) {
throw new Error('Listener must be a function')
}
if (!this.events[event]) {
this.events[event] = []
}
this.events[event].push(listener as Function)
}
emit(event: string, ...args: any[]) {
const listeners = this.events[event] || []
listeners.forEach(listener => {
if (isFunction(listener)) {
listener(...args)
}
})
}
}
const emitter = new EventEmitter()
// 添加有效監聽器
emitter.on('message', (data: any) => console.log('Received:', data))
// 嘗試添加無效監聽器
try {
emitter.on('error', 'not a function')
} catch (error) {
console.log('Error caught:', error.message) // Listener must be a function
}
emitter.emit('message', 'Hello World') // Received: Hello World
工具函數檢查
typescript
import { isFunction } from 'radash'
const utils = {
format: (value: any) => value.toString(),
validate: (value: any) => value !== null,
transform: 'not a function',
process: null
}
const functionUtils = Object.entries(utils)
.filter(([key, value]) => isFunction(value))
.reduce((acc, [key, value]) => {
acc[key] = value as Function
return acc
}, {} as Record<string, Function>)
console.log(Object.keys(functionUtils)) // ['format', 'validate']
異步函數檢查
typescript
import { isFunction } from 'radash'
const asyncFunctions = {
fetchData: async () => 'data',
processData: async (data: any) => data.toUpperCase(),
syncFunction: () => 'sync',
notFunction: 'string'
}
const validAsyncFunctions = Object.entries(asyncFunctions)
.filter(([key, value]) => isFunction(value))
.map(([key, value]) => ({
name: key,
isAsync: value.constructor.name === 'AsyncFunction'
}))
console.log(validAsyncFunctions)
// [
// { name: 'fetchData', isAsync: true },
// { name: 'processData', isAsync: true },
// { name: 'syncFunction', isAsync: false }
// ]
函數參數檢查
typescript
import { isFunction } from 'radash'
function analyzeFunction(func: unknown) {
if (!isFunction(func)) {
return { isValid: false, reason: 'Not a function' }
}
const f = func as Function
return {
isValid: true,
name: f.name || 'anonymous',
length: f.length,
isAsync: f.constructor.name === 'AsyncFunction',
isGenerator: f.constructor.name === 'GeneratorFunction'
}
}
console.log(analyzeFunction(() => {}))
// { isValid: true, name: 'anonymous', length: 0, isAsync: false, isGenerator: false }
console.log(analyzeFunction(async (a: number, b: number) => a + b))
// { isValid: true, name: 'anonymous', length: 2, isAsync: true, isGenerator: false }
console.log(analyzeFunction('not a function'))
// { isValid: false, reason: 'Not a function' }
函數組合
typescript
import { isFunction } from 'radash'
function compose(...functions: unknown[]) {
const validFunctions = functions.filter(isFunction) as Function[]
if (validFunctions.length === 0) {
return (x: any) => x
}
return (x: any) => validFunctions.reduceRight((acc, fn) => fn(acc), x)
}
const addOne = (x: number) => x + 1
const double = (x: number) => x * 2
const square = (x: number) => x * x
const composed = compose(square, double, addOne, 'not a function')
console.log(composed(5)) // 144 (5 + 1 = 6, 6 * 2 = 12, 12 * 12 = 144)
注意事項
- 函數類型: 檢查所有類型的函數(普通函數、箭頭函數、異步函數、生成器函數)
- 構造函數: 構造函數也被認為是函數
- 類: 類本身是函數(構造函數)
- 類型守衛: 作為TypeScript類型守衛使用
- 性能: 檢查速度很快,適合高頻使用
與其他方法的區別
isFunction()
: 檢查是否為函數typeof value === 'function'
: 原生JavaScript檢查value instanceof Function
: 檢查是否為Function實例value.constructor === Function
: 檢查構造函數
實際應用場景
- 事件處理: 驗證事件監聽器
- 回調函數: 驗證回調參數
- 插件系統: 驗證插件方法
- 中間件: 驗證中間件函數
- API設計: 驗證API回調
- 工具函數: 驗證工具函數參數