英文:
Why does the `instanceof` operator return false on instance passed to library? (No inheritance involved)
问题
In your code, the issue may be related to how the Client
class from your library's ssh2
dependency is compared with the Client
instance from the consumer code. It's possible that the TypeScript compiler is considering them as two different classes, even though they should be the same.
One way to ensure that the instanceof
check works as expected is to import the Client
class directly from your library's ssh2
dependency within your runCommand
function:
import { Client, ConnectConfig } from 'ssh2';
export function runCommand(params: Client | ConnectConfig) {
import { Client } from 'ssh2'; // Import 'Client' here as well
if (params instanceof Client) {
// do something
} else {
// create our own client
// do something
}
}
This should make sure that the Client
class used within the runCommand
function is the same as the one used in the consumer code, which should resolve the issue.
英文:
I am building a library with TS. This library uses the ssh2
library as a dependency.
I'm trying to create a function that can either accept an ssh2
configuration object or an already existing Client
instance to execute a command (this is a simplified case):
import { Client, ConnectConfig } from 'ssh2';
export function runCommand(params: Client | ConnectConfig) {
if(params instanceof Client) {
// do something
} else {
// create our own client
// do something
}
}
When I build this library and call the function like so:
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);
})
.connect({
host: "example.com",
port: 22,
username: "me",
privateKey: readFileSync(process.env.HOME + "/.ssh/id_ed25519"),
});
the instanceof
check in my function will return false
for some reason. What exactly is happening here? Is it a TS compilation issue or does Node.js see the Client
from my lib's dependency and my consumer code's dependency as two different classes?
The compiled code looks something like:
const ssh2_1 = require("ssh2");
//...
function runCommand(params) {
if (params instanceof ssh2_1.Client) {
// do something
}
else {
// create our own client
// do something
}
}
答案1
得分: 2
不显然的是,instanceof
运算符的行为中,类必须在 JavaScript 对象引用的父链中完全相同。
因此,如果您导入 Client
类两次,它们是不同的实际对象引用,而 instanceof
可能会产生"false"否定。
这很可能是这里发生的情况:ssh2
与您的库捆绑在一起,因此导入其自己的依赖项副本。而您的应用程序单独导入 ssh2
,导致单独的副本。
您有几个选项:
- 不要将依赖项与您的库捆绑在一起(例如使用 webpack 的
externals
),让应用程序安装单个版本,供您的库和应用程序都导入;这是指定peerDependencies
的典型情况 - 不要使用
instanceof
运算符;相反,使用一些启发式方法来确定对象是否具有您需要的结构;通常检查某些属性及其类型 - 从您的库中重新导出依赖项(例如,在您的情况下是
Client
类),并在您的应用程序中使用该依赖项(const { Client, runCommand } = require("myLib");
),这样它就是完全相同的副本(因为它已经捆绑了,为什么不重复使用它而不是重新捆绑它?)
英文:
What may not be obvious from the behaviour of instanceof
operator, is that the class must be exactly in the parent chain, in the sense of JavaScript object reference.
Hence, if you import Client
class twice, they are different actual object references, and instanceof
may give a "false" negative.
This is very probably what happens here: ssh2
is bundled with your library, hence it imports its own copy of the dependency. Whereas your app imports ssh2
on its own, leading to a separate copy.
You have a few options:
- Do not bundle the dependency with your library (e.g. with webpack
externals
), let the app install a single version that both your library and app will import; typical case of specifyingpeerDependencies
- Do not use the
instanceof
operator; instead, use some heuristic to determine whether the object has the shape you need; typically check for some properties and their type - Re-export the dependency (e.g.
Client
class in your case) from your library, and use that one in your app (const { Client, runCommand } = require("myLib");
), so that it is the exact same copy (since it is already bundled, why not re-using it instead of re-bundling it?)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论