Dynamically import module in TypeScript
Asked Answered
C

4

50

What is the TypeScript way of loading modules dynamically (path to the module is known at runtime)? I tried this one:

var x = "someplace"
import a = module(x)

But it seems that TypeScript compiler would like to see path as a string in import/module at compile time:

$ tsc test.ts 
/tmp/test.ts(2,19): error TS1003: Identifier expected.
/tmp/test.ts(2,20): error TS1005: ';' expected.

I know I can for example directly use RequireJS (if I use amd module format), but that doesn't feel right to me - it's solution for one particular library.

Cissy answered 8/8, 2013 at 5:1 Comment(2)
With TypeScript 0.9.1 instead of 'module' you now need to use 'require' Try changing your import to: import a = require(x)Ottava
@hnuecke: you mean const a = require('x')?Meridethmeridian
P
87

ES proposal dynamic import is supported since TypeScript 2.4. Document is here.

import function is asynchronous and returns a Promise.

var x = 'someplace';
import(x).then((a) => {
  // `a` is imported and can be used here
});

Or using async/await:

async function run(x) {
  const a = await import(x);
  // `a` is imported and can be used here
}
Pteropod answered 24/7, 2017 at 14:22 Comment(1)
Definitely wouldn't have guessed this one!Ancillary
T
20

You need to specify a hard coded string. Variables will not work.

Update

JavaScript now got dynamic imports. So you can do import(x) :https://developers.google.com/web/updates/2017/11/dynamic-import

TypeScript supports it as well. That said you would still want the argument to be statically analyzable for type safety e.g.

const x = 'someplace';
import(x).then((a) => { // TypeScript knows that `x` is 'someplace' and will infer the type of `a` correctly
}); 
Tuggle answered 8/8, 2013 at 5:57 Comment(0)
K
6

If you want to extract the type from a default export dynamically it can be done like so:

    const dynamicImport = await import('path-to-import')
    const typedDefaultImport = dynamicImport.default
Kovrov answered 12/9, 2022 at 18:32 Comment(0)
S
1

I've tried the option without extension, but for me fails in javascript and typescript side going directly to the catch.

So I've made a workaround including an additional parameter to my function that is 'js' by default.

export const getPackageConfiguration = async (cmdr: Pick<CommanderPackage, 'cmd'>, ext: 'js' | 'ts' = 'js') => {
  try {
    const config = await import(`./managers/${cmdr.cmd}.${ext}`)
    return config?.default
  } catch {
    return {}
  }
}

It work well when I build my files with tsc command generating js files. And when I run my test (typescript side), I call it with 'ts' to avoid import errors.

await getPackageConfiguration('npm', 'ts')
Speculative answered 20/9, 2023 at 17:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.