2

I have a Typescript file (colorTheme.ts) that looks like this:

export default (async (key) => {
  console.log(key)
  const themeImport = await import(`../build/theme/${key}/color.js`)
  return themeImport
})()

And then I reference this function from a separate Typescript file like so:

import colorTheme from '../colorTheme'

colorTheme('test').then(color => {
  // do stuff
})

However, I get an error:

TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'Promise' has no compatible call signatures.

I've googled around and tried things like:

export default (async (key: string) => {
  console.log(key)
  const themeImport = await import(`../build/theme/${key}/color.js`)
  return themeImport
})()

But to no avail. Typescript isn't my forte, it's a preexisting environment that I'm trying to work in. From what I understand I need to somehow setup types for the Promise maybe? But I'm not sure how to do that.

Update: Added a bit more fuller code sample for what I'm trying to do.

7
  • What you are trying to do here using an IIFE is to export a Promise. Because you are executing an async function and returns it (an async function returns a Promise). What are you trying to do ? I don't think that returning a Promise is something viable importing a file Commented Apr 24, 2019 at 14:39
  • Updated the code examples with a little more context. Commented Apr 24, 2019 at 14:41
  • const themeImport = await import(`../build/theme/${key}/color.js`) eeeuh I'm not sure it will ever work. Unless import is not a regular import, such code will be transpiled, so you won't be able to resolve the import at runtime on the compiled code. Also, the self invoking anonymous function will never get the key argument. Is there any reason to use an IIFE here?.. Commented Apr 24, 2019 at 14:42
  • It works if I pass in the key value manually (e.g. async() => { const key = 'test' ...). It's the ability to be able to pass dynamic keys via the function call that seems to be giving me the problem. Commented Apr 24, 2019 at 14:45
  • Of course if you declare it it will work, the question is why you're using an IIFE. It's overcomplicated, you just need to export a function that should return a promise. IIFE are not meant to be used in this way, keep in mind that the above code will be executed immediately due to the nature of IIFE, I don't think this is what you want ;) Commented Apr 24, 2019 at 14:47

1 Answer 1

4

Give a look at the two trailing parenthesis:

(async (x) => {
  console.log(x)
})() <--

You are executing the function as you declare it. This is a so-called IIFE: Immediately Invoked Function Expression.

Let's split the export adding a variable:

const result = (async (x) => {
  console.log(x)
})();

export default result;

What's the value of result? Well, the value of result is equal to the return value of the function. If it was a normal function, this was equal to a function immediately resolved as undefined. Since it is an async function and we aren't returning anything, this means that the returned value is a Promise of undefined.

So what you are exporting is an already resolved promise! But... what about the parameter x?

Well, the function accepts a parameter x, but you are actually passing nothing. Watch again the trailing parenthesis, there is nothing inside, so you will see undefined in the console if you execute the code.

If instead you passed an argument, for example a string, you saw that string:

(async (x) => {
  console.log(x) // It prints banana!
})('banana')

So here is the point where you have to pass the argument, then the function gets immediately invoked and the result is exported.

Let's rewrite colorTheme.ts in a simpler way:

1. Add a variable

const result = (async (x) => {
  console.log(x)
})();

export default result;

2. Return undefined (it's the same of not returning)

const result = (async (x) => {
  console.log(x)
  return undefined;
})();

export default result;

3. Use Promise in place of async

const result = (x => {
  console.log(x)
  return Promise.resolve(undefined);
})();

export default result;

4. Don't invoke the function immediately

const f = function (x) {
  console.log(x)
  return Promise.resolve(undefined);
}

const result = f(undefined);

export default result;

So, this is basically what you exported. Now it ups to you to fix it according to what you want to get!

Sign up to request clarification or add additional context in comments.

2 Comments

Ahh okay, this makes sense now. Thank you for the detailed reply!
I added more details. I made everything explicit, since many things are often implicit and someone could not know them

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.