Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to support several versions of the same module with typescript?

I'm making a typescript npm package.
It uses discord.js, but there's two main version of discord.js:
* discord.js 11.5
* discord.js v12.0.0-dev

I'd like my module to support both version. I mean, users can install the version of discord.js they want and the package will use the good code.

For another project, in javascript (without typescript), I use this:

const { version } = require("discord.js");
if(version === "12.0.0-dev"){
    // code for v12
} else {
    // code for v11
}

and it works perfectly. But, with typescript, it's more complicated, due to typings. Indeed, discord.js typings aren't the same in v11 and in v12, so I can't compile the code with both versions:

const { Guild, version } = require("discord.js");
if(version === "12.0.0-dev"){
    Guild.iconURL(); // for v12
} else {
    Guild.iconURL; // for v11
}

if the v12 is installed, it will throw iconURL() doesn't exist on Guild and if it's v11, iconURL doesn't exist on Guild.
Is there any way to support both versions in the same package, without creating a branch for each version?

like image 345
Androz2091 Avatar asked Feb 23 '20 11:02

Androz2091


1 Answers

Although not ideal, you could manually download the typings for v11 and v12 and change the module name to something like this:

// [email protected]
declare module 'discord.js@11' {
  ...
}

// [email protected]
declare module 'discord.js@12' {
  ...
}

Then you can import the types like this:

import { Guild as Guild12, version } from "discord.js";
import { Guild as Guild11 } from "discord.js@11";

declare const guild: Guild11 | Guild12 // obviously wouldn't be declared like this in your actual code

// At the time of writing v12.0.2 has been released
if (version === "12.0.2") {
    (guild as Guild12).iconURL(); // for v12
} else {
    (guild as Guild11).iconURL; // for v11
}

You can also define a type guard:

function isV12(guild: Guild11 | Guild12): guild is Guild12 {
  return version === "12.0.2";
}

if (isV12(guild)) {
  guild.iconURL();
} else {
  guild.iconURL();
}

I tried aliasing discord@11 and discord@12 like this in package.json:

"devDependencies": {
  "discord.js11": "npm:[email protected]",
  "discord.js12": "npm:[email protected]"
}

but I got this error:

import { Guild as Guild12, version } from "discord.js12";
//                                        ~~~~~~~~~~~~~~
// with pnpm:
// File '/path/to/project/node_modules/.pnpm/registry.npmjs.org/discord.js/12.0.2/node_modules/discord.js/typings/index.d.ts' is not a module. (ts2306)
// with npm:
// File '/path/to/project/node_modules/discord.js12/typings/index.d.ts' is not a module. (ts2306)
like image 123
cherryblossom Avatar answered Nov 12 '22 14:11

cherryblossom