TypeScript compiler - Failed to load node typings

Hello everybody,

I’m trying to use a library called TypeORM in my Ionic App. The library is originally written for node but it also runs in the browser. When using it in an empty cordova project everything transpiles fine but I can’t get the library to transpile in an Ionic project because it seems like the compiler ignores @types/node and therefore gives errors like Cannot find name 'Buffer'.
I have tried installing @types/node via npm and also added it to the tsconfig.json file with typeRoots and types but the error doesn’t change. Is there another way to tell Ionic about the types since they work as expected in VS Code (including intellisense).

Thanks in advance to everyone!

package.json

{
  "name": "bethabara-v2",
  "version": "0.0.1",
  "author": "Ionic Framework",
  "homepage": "http://ionicframework.com/",
  "private": true,
  "scripts": {
    "clean": "ionic-app-scripts clean",
    "build": "ionic-app-scripts build",
    "lint": "ionic-app-scripts lint",
    "ionic:build": "ionic-app-scripts build",
    "ionic:serve": "ionic-app-scripts serve"
  },
  "dependencies": {
    "@angular/common": "4.1.3",
    "@angular/compiler": "4.1.3",
    "@angular/compiler-cli": "4.1.3",
    "@angular/core": "4.1.3",
    "@angular/forms": "4.1.3",
    "@angular/http": "4.1.3",
    "@angular/platform-browser": "4.1.3",
    "@angular/platform-browser-dynamic": "4.1.3",
    "@ionic-native/core": "3.12.1",
    "@ionic-native/splash-screen": "3.12.1",
    "@ionic-native/status-bar": "3.12.1",
    "@ionic/storage": "2.0.1",
    "@types/node": "^8.0.26",
    "cordova-android": "^6.2.3",
    "cordova-plugin-console": "^1.0.5",
    "cordova-plugin-device": "^1.1.4",
    "cordova-plugin-splashscreen": "^4.0.3",
    "cordova-plugin-statusbar": "^2.2.2",
    "cordova-plugin-whitelist": "^1.3.1",
    "cordova-sqlite-storage": "^2.0.4",
    "ionic-angular": "3.6.0",
    "ionic-plugin-keyboard": "^2.2.1",
    "ionicons": "3.0.0",
    "reflect-metadata": "^0.1.10",
    "rxjs": "5.4.0",
    "sw-toolbox": "3.6.0",
    "typeorm": "0.1.0-alpha.35",
    "zone.js": "0.8.12"
  },
  "devDependencies": {
    "@ionic/app-scripts": "2.1.4",
    "ionic": "3.9.2",
    "typescript": "2.3.4"
  },
  "description": "An Ionic project",
  "cordova": {
    "plugins": {
      "cordova-sqlite-storage": {},
      "cordova-plugin-console": {},
      "cordova-plugin-device": {},
      "cordova-plugin-splashscreen": {},
      "cordova-plugin-statusbar": {},
      "cordova-plugin-whitelist": {},
      "ionic-plugin-keyboard": {}
    },
    "platforms": [
      "android"
    ]
  }
}
$ ionic info

cli packages: (path)

    @ionic/cli-utils  : 1.9.2
    ionic (Ionic CLI) : 3.9.2

global packages:

    Cordova CLI : 7.0.1

local packages:

    @ionic/app-scripts : 2.1.4
    Cordova Platforms  : android 6.2.3
    Ionic Framework    : ionic-angular 3.6.0

System:

    Android SDK Tools : 26.0.2
    Node              : v6.9.5
    npm               : 3.10.10
    OS                : Windows 10

Side point: your version of Node has a security flaw. Update strongly recommended.

Question about your question: you can get it working in Angular 2 no problem? It’s only compile-time type checking that’s the issue?

There is zero reason for you to care about my opinion whatsoever.

If you do, it is that after several years of dealing with various ORMs (admittedly in C++, Java, and Golang, not JavaScript), I came to the conclusion that they are more trouble than they are worth. If you are willing to consider life without ORMs, maybe we can make your life easier and more productive.

@rapropos: I’ve had my fair share of troubles with ORMs but for a complex database model I don’t feel like writing queries myself or implementing an abstraction layer myself. What would be your advice in this situation?

@AaronSterling: Thanks for pointing out my Node version. I updated to 6.11.2 LTS
The interesting part about the types is, that I have them when developing and when I run tsc directly there is no error but as soon as I run ionic-app-scripts build I get the mentioned compile error. Btw, the same happens in a fresh angular2 app, tsc works, ng serve doesn’t.

I don’t know much about your app, but speaking in general I prefer to offload complex database model stuff to a server and have apps deal only with JSON that makes their lives easier. Obviously, that’s not always possible, but I would say (completely uninformed and generalizing) that if your app has complex enough interaction with offline data, you are probably going to be happier in the long run writing tailored query providers than you would be bookending a generic ORM.

One of the requirements given is, that it works offline. Therefore I have to create the database model in the app and keep data up-to-date. Otherwise I would love to just use JSON

Is this something I should/can report as a bug of ionic-app-scripts?

I accomplish that through Redux and long term local storage. The cache manager listens to database timestamps, and gets an update from the database if the timestamps change. (So even realtime messaging is kind of “offline with online support”.) But in the long term, I’m interested in supporting any query expressible in OWL DL, so the TypeORM library intrigues me, hadn’t heard of it before, thank you. I don’t know whether rolling my own query manager would be easier or harder than leveraging an ORM, so I have no position on the advice of @rapropos.

Is there a namespace file like @types/typeorm ?

Not that I am aware of but the problem is not that the compiler doesn’t no about the TypeORM types but rather about Node’s types and methods like Buffer or require.

Thanks for the tip with Redux. I will have a look at it.

I had a possibly similar issue with NodeJS.Timer a while back. What does your tsconfig.json look like?

Right now it looks like this:

{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "declaration": false,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "lib": [
      "dom",
      "es2015"
    ],
    "module": "es2015",
    "moduleResolution": "node",
    "sourceMap": true,
    "target": "es5"
  },
  "include": [
    "src/**/*.ts"
  ],
  "exclude": [
    "node_modules"
  ],
  "compileOnSave": false,
  "atom": {
    "rewriteTsconfig": false
  }
}

but I also tried adding

"typeRoots": [
   "node_modules/@types"
 ]

and

"types" : [ "node" ]

but it doesn’t change anything. Are does properties used when compiling the app because while testing it I added a none existing types file to the list and the compiler didn’t complain.

Looking back on my code, I solved that issue by cheating – the compiler recognizes NodeJS.Timer if set implicitly, but not when declared explicitly. So I just used implicit typing for that.(const timer = setTimeout blah blah, and timer is understood to be type NodeJS.Timer.) I would have tried what you tried in tsconfig. No further advice there, sorry. Good luck!

1 Like

Thanks anyway for helping! Should I create an issue for it or wait and see if someone else here knows a way around?

I don’t know how long is appropriate to wait. If you do post an issue somewhere, please post the link here. I’d like to clean up my code, and I think I’m facing the same error or misunderstanding that you are.

I created an Issue for it in ionic-app-scripts

1 Like

So it turns out, that I added the typeRoots property but not in the compilerOptions.
This is the working tsconfig.json:

{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "declaration": false,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "lib": [
      "dom",
      "es2015"
    ],
    "module": "es2015",
    "moduleResolution": "node",
    "sourceMap": true,
    "target": "es5",
    "typeRoots": [
      "node_modules/@types"
    ]
  },
  "include": [
    "src/**/*.ts"
  ],
  "exclude": [
    "node_modules"
  ],
  "compileOnSave": false,
  "atom": {
    "rewriteTsconfig": false
  }
}

I don’t know if this will also work for you @AaronSterling.

I added that, and reinstated the NodeJS.Timer declaration, and the prod build goes through fine. I don’t understand TypeScript well enough to know if there are any unintended consequences of setting typeRoots that way, but I suppose I’ll find out! Thanks for the suggestion.