Search code examples
javascripttypescripttypescript-typingssweetalert2javascript-import

Using SweetAlert2 with TypeScript, could not find a declaration file for module 'sweetalert2/dist/sweetalert2.js'


I'm migrating one of my projects to TypeScript, in that project SweetAlert2 library is used.

The default way to import SweetAlert2 (both JS and CSS) is

import Swal from 'sweetalert2'

This works fine with TypeScript because there are types in the library: https://github.com/sweetalert2/sweetalert2/blob/master/sweetalert2.d.ts

But in my project the way of importing is this:

import Swal from 'sweetalert2/dist/sweetalert2.js'

This is import for JS only, without styles. With this type of import, I'm getting the TS error:

Could not find a declaration file for module 'sweetalert2/dist/sweetalert2.js'. 

ts(7016)

I tried to copy sweetalert2/sweetalert2.d.ts to sweetalert2/dist/sweetalert2.d.ts, but got another error:

File 'node_modules/sweetalert2/dist/sweetalert2.d.ts' is not a module. 

ts(2306)

What's going on here and why TS complains about dist/sweetalert2.d.ts is not a module?


Solution

  • The current type definitions of SweetAlert does not provide typings for "submodules". When you use the declare module syntax like this, you type the whole package "at once" (what an user gets when importing from ^sweetalert2$), but you're not describing what's in the individual compiled files in dist/ exactly, so yes, they can't be targeted explicitly.

    Try removing the declare module block entirely in your copied file. Then, use declare namespace Swal, and it'll work.

    We should be able to modify the declaration files of sweetalert2 so both simple import and the import of sub-files work.

    Take a look at how I typed graphql-compose so this becomes possible: graphql-compose

    Each .js file has a .d.ts counterpart, and there is no longer one single file that describes the whole module with declare module.

    Edit: I tried this approach in you repro, this works well, and we're able to type sweetalert2.all.js as well. The following solution may be simpler though (less files, simpler build scripts). The 1:1 mapping approach is better but is probably more suited to larger libraries.

    Another possibility is to add declare module 'sweetalert2/dist/{**}' entries to the single sweetalert2.d.ts file, that reexports the default module contents for each dist/ variant:

    declare module 'sweetalert2' {
        // Current contents of the file, unchanged
    }
    
    declare module 'sweetalert2/dist/sweetalert2.js' {
        export * from 'sweetalert2';
        // "export *" does not matches the default export, so do it explicitly.
        export { default } from 'sweetalert2';
    }
    
    declare module 'sweetalert2/dist/sweetalert2.all.js' {
        export * from 'sweetalert2';
        export { default } from 'sweetalert2';
    }