为何传入库的实例在instanceof校验中返回false?(无继承场景)
ssh2 Client实例instanceof校验返回false的原因与解决
问题场景
使用TypeScript开发依赖ssh2的工具库时,编写了支持接收ssh2的Client实例或ConnectConfig配置对象的runCommand函数:
import { Client, ConnectConfig } from 'ssh2'; export function runCommand(params: Client | ConnectConfig) { if(params instanceof Client) { // 处理已有Client实例的逻辑 } else { // 创建新Client并执行命令的逻辑 } }
编译后在消费代码中调用时,传入的Client实例始终无法通过instanceof校验(返回false):
const { readFileSync } = require("fs"); const { Client } = require("ssh2"); const { runCommand } = require("myLib"); const conn = new Client(); conn .on("ready", () => { console.log("Client :: ready"); runCommand(conn); // 传入的conn无法通过instanceof校验 }) .connect({ host: "example.com", port: 22, username: "me", privateKey: readFileSync(process.env.HOME + "/.ssh/id_ed25519"), });
工具库编译后的核心逻辑片段:
const ssh2_1 = require("ssh2"); //... function runCommand(params) { if (params instanceof ssh2_1.Client) { // 处理逻辑 } else { // 创建新Client的逻辑 } }
原因分析
这不是TypeScript编译问题,核心原因是Node.js的模块解析机制导致工具库和消费端加载了两个独立的ssh2包实例:
- 工具库的
ssh2是安装在自身node_modules目录下的私有依赖 - 消费端的
ssh2是安装在项目根目录node_modules下的依赖 - JavaScript中
instanceof的校验依赖构造函数的引用一致性,两个不同包中的Client类是完全独立的构造函数,因此消费端创建的实例无法匹配工具库中的ssh2_1.Client
解决方案
1. 将ssh2声明为peer依赖
修改工具库的package.json,把ssh2从dependencies移到peerDependencies,强制消费端提供统一版本的ssh2:
{ "peerDependencies": { "ssh2": "^x.y.z" // 填写兼容的版本范围 } }
这样工具库会直接复用消费端安装的ssh2版本,确保Client构造函数的引用一致。
2. 替换instanceof校验逻辑
如果无法修改依赖声明,可以通过其他方式识别Client实例:
- 检查构造函数名称:
if (params.constructor.name === 'Client') { // 处理逻辑 }
- 检查实例的特征方法/属性:
if (typeof params.connect === 'function' && typeof params.on === 'function') { // 处理逻辑 }
- 使用
Object.prototype.toString判断类型:
if (Object.prototype.toString.call(params) === '[object Client]') { // 处理逻辑 }
内容的提问来源于stack exchange,提问作者Kerim Güney
相关产品推荐
相关产品推荐

