TypeScript运行时类型自省:如何区分NodeFilter与EdgeFilter类型函数
方案1:拆分API,从设计层面规避运行时判断 (最推荐)
完全不需要做运行时类型校验,编译期就能完成所有类型检查,语义清晰调用成本极低:
class Graph { // 独立的节点过滤方法 filterNodes(filter: NodeFilter): Graph { const newNodes = this.nodes.filter(filter) return new Graph(newNodes, [...this.edges]) } // 独立的边过滤方法 filterEdges(filter: EdgeFilter): Graph { const newEdges = this.edges.filter(filter) return new Graph([...this.nodes], newEdges) } // 可选保留原统一入口做兼容 filter(filter: NodeFilter | EdgeFilter): Graph { // 内部用后面的类型判断逻辑实现即可 } }
这个方案没有任何运行时额外开销,也不会出现调用方传错过滤器的问题,是所有方案里性价比最高的选择。
方案2:带标记的过滤器封装(适合需要保留统一filter入口的场景)
你之前给函数加type属性的思路可以通过工厂函数优化,避免手动加标记漏写的问题:
// 定义带标记的过滤器类型 type NodeFilter = { type: 'NodeFilter' (node: Node): boolean } type EdgeFilter = { type: 'EdgeFilter' (edge: Edge): boolean } // 工厂函数自动加标记,强制类型校验 const createNodeFilter = (filter: (node: Node) => boolean): NodeFilter => { return Object.assign(filter, { type: 'NodeFilter' as const }) } const createEdgeFilter = (filter: (edge: Edge) => boolean): EdgeFilter => { return Object.assign(filter, { type: 'EdgeFilter' as const }) } // 类型守卫实现运行时判断 function isNodeFilter(filter: unknown): filter is NodeFilter { return typeof filter === 'function' && (filter as any).type === 'NodeFilter' } function isEdgeFilter(filter: unknown): filter is EdgeFilter { return typeof filter === 'function' && (filter as any).type === 'EdgeFilter' } // 使用示例 const filter = createNodeFilter(node => node.weight > 10)
这个方案比手动给每个函数加属性更安全,TS编译期会强制你走工厂函数创建过滤器,不会出现漏加标记的问题。
方案3:可调用类实例(适合过滤器需要携带状态的复杂场景)
你提到的可调用类方案完全可行,运行时可以直接用instanceof判断,不需要额外写类型守卫:
abstract class BaseFilter { abstract type: 'NodeFilter' | 'EdgeFilter' abstract exec(value: Node | Edge): boolean } class NodeFilter extends BaseFilter { type: 'NodeFilter' = 'NodeFilter' constructor(private filterFn: (node: Node) => boolean) { super() } exec(node: Node): boolean { return this.filterFn(node) } } class EdgeFilter extends BaseFilter { type: 'EdgeFilter' = 'EdgeFilter' constructor(private filterFn: (edge: Edge) => boolean) { super() } exec(edge: Edge): boolean { return this.filterFn(edge) } } // 运行时判断逻辑 if (filter instanceof NodeFilter) { nodes = nodes.filter(n => filter.exec(n)) } else if (filter instanceof EdgeFilter) { edges = edges.filter(e => filter.exec(e)) }
这个方案适合过滤器需要存储额外配置、复用过滤逻辑的场景,缺点是比纯函数多了一点类实例的开销。
内容的提问来源于stack exchange,提问作者bgoosman
相关产品推荐
相关产品推荐

