Background: TypeScript checks the modules that you try and import, and fails at compile-time if a string literal is used that does not match the name of an actual module or path to a supported file type.
For example import {Component} from 'react'
and import item from './item'
compile fine, but import {Component} from 'reactt'
and import item from './otem'
would fail to compile assuming that there is a react
module installed and an item.ts
file in the project but no reactt
module installed and no ./otem
file with the extensions .ts, .js, .json, etc in the project.
Problem: I'm not sure how to create a function where one of the arguments is a string literal that must correspond to an actual module or supported file.
function customImportEffect(moduleName: module_string_literal) {
...
}
What type should module_string_literal
be so that compile-time checking fails when incorrect inputs such as 'reactt'
or './otem'
are supplied as arguments?
Reason for asking: I am trying to make a webpack file transformer (a.k.a. a loader) which adds code to the top of TypeScript files before they are transpiled, so users can have type-safe hot module reloading code. For example, imagine the following code being inserted above every typescript file before being transpiled to JS:
class HotModule {
public static accept(moduleName: module_string_literal, onModuleReplace: Function(updatedModule: typeof import(moduleName)):void) {
if(module.hot) {
module.accept(moduleName.toString(), function() {
onUpdate(require(moduleName.toString()))
}
}
}
}
Then hot module reloading could be type-safe and appear more clean. Assuming that the default export from the ./item.ts file is an object with a member named message
, one could write
HotModule.accept("./item", ({message: newMessage}) => {
const oldMessage = message;
messages[messages.indexOf(oldMessage)] = message = newMessage;
}
to implement hot reloading of the message instead of
if(module.hot) {
module.hot.accept("./item", function() {
const oldMessage = message;
messages[messages.indexOf(oldMessage)] = message = require("./item");
}
}
I am hoping this may be possible because since TypeScript v2.4 there has been the ability to asynchronously dynamically import modules, and the string literal supplied is checked for correctness, and incorrect string literals cause a compile-time failure.
Currently I'm just including "types": ["webpack-env"]
in the compilerOptions
object in my tsconfig.json
file, but I'd like a hot module API which takes better advantage of TypeScript's checking toolset.
make a module-type.d.ts somewhere with the content
you will need to enable jsonmodule in your tsconfig
then you import it wherever you need it