56

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.

2
  • 2
    With TypeScript 0.9.1 instead of 'module' you now need to use 'require' Try changing your import to: import a = require(x) Commented Aug 17, 2013 at 20:30
  • @hnuecke: you mean const a = require('x')? Commented Apr 3, 2020 at 0:17

4 Answers 4

96

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
}
Sign up to request clarification or add additional context in comments.

1 Comment

Definitely wouldn't have guessed this one!
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
}); 

Comments

7

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

Comments

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')

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.