javascript - Prečo operátor `instanceof` vracia false pre inštanciu odovzdanú do knižnice? (Žiadna dedičnosť neprichádza do úvahy)
Staviam knižnicu v TS. Táto knižnica používa knižnicu ssh2 ako závislosť.
Snažím sa vytvoriť funkciu, ktorá môže buď prijať ssh2 konfiguračný objekt alebo už existujúcu inštanciu Client na vykonanie príkazu (toto je zjednodušený prípad):
import { Client, ConnectConfig } from 'ssh2';
export function runCommand(params: Client | ConnectConfig) {
if(params instanceof Client) {
// do something
} else {
// create our own client
// do something
}
}
Keď zostavím túto knižnicu a zavolám funkciu takto:
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"),
});
kontrola instanceof v mojej funkcii z nejakého dôvodu vráti false. Čo sa tu presne deje? Je to problém s kompiláciou TS alebo Node.js vidí Client zo závislosti mojej knižnice a zo závislosti môjho klientského kódu ako dve rôzne triedy?
Zostavený kód vyzerá nejako takto:
const ssh2_1 = require("ssh2");
//...
function runCommand(params) {
if (params instanceof ssh2_1.Client) {
// do something
}
else {
// create our own client
// do something
}
}
Odpoveď č. 1
Čo nemusí byť zjavné z chovania operátora instanceof, je, že trieda musí byť presne v reťazci rodičov, v zmysle JavaScript objektovej referencie.
Preto, ak naimportujete triedu Client dvakrát, ide o rôzne skutočné referencie objektov a instanceof môže dať „false“ negatívny výsledok.
Toto je veľmi pravdepodobne to, čo sa tu deje: ssh2 je zabalený vo vašej knižnici, preto importuje svoju vlastnú kópiu závislosti. Zatiaľ čo vaša aplikácia importuje ssh2 sama, čo vedie k samostatnej kópii.
Máte niekoľko možností:
- Neposkytujte závislosť spolu s vašou knižnicou (napr. pomocou webpack
externals), nech aplikácia nainštaluje jednu verziu, ktorú budú importovať ako vaša knižnica, tak aj aplikácia; typický prípad špecifikovaniapeerDependencies - Nepoužívajte operátor
instanceof; namiesto toho použite nejakú heuristiku na určenie, či objekt má tvar, ktorý potrebujete; typicky skontrolujte niektoré vlastnosti a ich typ - Re-exportujte závislosť (napr. triedu
Clientvo vašom prípade) z vašej knižnice a používajte túto vo vašej aplikácii (const { Client, runCommand }=require("myLib");), aby to bola presne tá istá kópia (keďže je už zabudovaná, prečo ju znovu nezabaliť namiesto opätovného balenia?)