Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript - Import module if exist

Tags:

How to import a module if it exists ?

I have 2 projects, client & server. Both import one same file.
The file imports a node module which is only installed in the server project. The client doesn't have the module.
So the require must return the module typed when opened from the server project.
And it must return undefined when opened from the client project.

Below an screenshot from the client project. Typescript doesn't compile because it says it cannot find the module. Typescript require cannot find module type-graphql

A simple require doesn't keep the type: enter image description here

like image 233
Yairopro Avatar asked Dec 11 '19 19:12

Yairopro


1 Answers

There are 2 parts to this:

  1. A formal import statement must be unconditional. import means the module must always exist. That doesn't mean it has to be the module you actually need.
  2. The desired type is module | undefined on the server side. But on the client side module is unknowable. So to allow for server based calls, we should allow any fields to be used, like {[k:string]:any}, and we need to be able to select which one is appropriate for the side we are on.

So your best bet is probably to add an empty module of the same name to your client side, so a file called type-graphql.ts in the node_modules folder on the client side that only contains:

export {}

This way the unconditional import will always work, client will import this empty module file and server will import the actual library. Then you just need to re-assign the variable to consider possible interfaces:

import * as _TypeGraphQL from 'type-graphql';

// don't check methods on the client side, if we had type definitions on both we could just use that
type CLIENT_SIDE_INTERFACE = {[k:string]:any};
// on server side we can check for case that the module is not present.
type SERVER_SIDE_INTERFACE = typeof _TypeGraphQL | {"ISDUMMY":true}

// if the imported module has our indicator key then we are on the client side
type THIS_SIDE_INTERFACE = "ISDUMMY" extends (keyof typeof _TypeGraphQL) ? CLIENT_SIDE_INTERFACE : SERVER_SIDE_INTERFACE

const TypeGraphQL: THIS_SIDE_INTERFACE = _TypeGraphQL;

After having it pointed out that putting files in the normal node_modules folder is problematic, I can offer a possible solution to this as well.

Node resolves modules (that don't start with ./ or /) by walking up the folder tree from the current file, each level seeing if there is a folder called node_modules. Normally this means in the root of your project there is one folder containing all the modules. However you can add another folder in the middle of your project called node_modules and any imports by files there will search that folder first.

So for a folder structure like this would let you put the dummy file in the project in a way that import * as a from 'test-graphql' will import from a stable folder:

root
- node_modules
- src
  --- SUBFOLDERS
        - node_modules
          -test-graphql.tsx (dummy code)
        - git-sub-module
          - wrapper.tsx (containing the import code mentioned above)

Code in the wrapper.tsx in this case would try to import from the inner node_modules importing the empty module file. Just make sure you add sufficient comments in the empty module explaining what sorcery is going on :)

like image 154
Tadhg McDonald-Jensen Avatar answered Sep 30 '22 19:09

Tadhg McDonald-Jensen