Repository: TypeScript
Issue: Computed import types
Labels: Suggestion,Awaiting More Feedback

# Suggestion

<!--
  Please fill in each section completely. Thank you!
-->

## 🔍 Search Terms

<!--
  💡 Did you know? TypeScript has over 2,000 open suggestions!
  🔎 Please search thoroughly before logging new feature requests as most common ideas already have a proposal in progress.
  The "Common Feature Requests" section of the FAQ lists many popular requests: https://github.com/Microsoft/TypeScript/wiki/FAQ#common-feature-requests

  Replace the text below:
-->

```
import label:feature-request
```

## ✅ Viability Checklist

<!--
   Suggestions that don't meet all these criteria are very, very unlikely to be accepted.
   We always recommend reviewing the TypeScript design goals before investing time writing
   a proposal for ideas outside the scope of the project.
-->
My suggestion meets these guidelines:

* [x] This wouldn't be a breaking change in existing TypeScript/JavaScript code
* [x] This wouldn't change the runtime behavior of existing JavaScript code
* [x] This could be implemented without emitting different JS based on the types of the expressions
* [x] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
* [x] This feature would agree with the rest of [TypeScript's Design Goals](https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals).


## ⭐ Suggestion

Add ability to `typeof import()` a string literal type

## 📃 Motivating Example

```ts
declare module 'test' {
    export const test: number;
}

type GetExport<T extends string> = typeof import(T)

type Test = GetExport<'test'> // typeof import('test') ≈ {test: number}
```

## 💻 Use Cases

`babel`, `eslint` and `webpack` use package names in their API, dynamically `require` them and proxy data into their interface. Generally, API that looks like

```ts
doSomething({
    package: 'package-name',
    options: {
        optionForThisPackage: 'value',
    },
});
```

could greatly improve on typing with this.

Also it's often the case with dynamic imports that resulting `Promise` gets passed through several other methods (like `React.lazy` or `loadable` from `@loadable/component`). Currently the only way to get good types there is to have these duplicated at every `import()` site. It would be possible to assign some types to wrapper function in this case too.

```ts
type LazyRegistry<Packages extends Record<string, string>> = {
    [Name in keyof Packages]: Promise<(typeof import(Name))[Packages[Name]]>
}
const lazyRegistry = <Packages extends Record<string, string>>(packages: Packages): LazyRegistry<Packages> => {
    return Object.fromEntries(
        Object.entries(packages).map(([name, importName]) => {
            const lazy = React.lazy(async () => {
                return (await import(name))[importName];
            });
            return [key, lazy] as const;
        }),
    ) as LazyRegistry<Packages>;
};

type LoadableRegistry<Packages extends Record<string, string>> = {
    [Name in keyof Packages]: AsLoadableComponent<typeof import(Packages[Name])>
}
const loadableRegistry = <Packages extends Record<string, string>>(packages: Packages) => {
    return Object.fromEntries(
        Object.entries(packages).map(([name, importName]) => {
            return [key, loadable(() => import(importName))] as const;
        }),
    ) as LoadableRegistry<Packages>;
};

const DynamicComponentRegistry = someRegistry({
    Foo: 'Foo',
    Bar: 'Bar',
});
```