microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
101.13k stars 12.5k forks source link

`typeRoots` is not resolved as part of compilation #27026

Closed mihailik closed 5 years ago

mihailik commented 6 years ago

TypeScript Version: 3.0.1 and 3.1.0-dev.20180907 (Windows 7, everything on local C:\ drive)

I can't make typeRoots to work at all. There is a lot of similar complaints over Stackoverflow and elsewhere, but I don't see a single complete workable example. So here's a simplest reproduction case. It doesn't work for me.

In summary, I install three.js from NPM into node_modules, but want to use typings from local directory. For simplicity those are exact same types you get from @types/three — without any modifications.

Code

Project structure:

node_modules
   three  <------------ installed as usual with  "npm install three"
src
   package
      three   <------------ exact copy of typings for three.js
      webvr-api

useThree.ts
tsconfig.json

useThree.ts:

import * as THREE from "three";

function main(s: THREE.AmbientLight) {
}

tsconfig.json

{
   "compilerOptions": {
       "typeRoots" : ["./src/package"],
       "strict" : true
   }
}

Trying to compile with:

tsc.cmd  -p tsconfig.json

Expected behavior: Compile successfully. Also show suggestions when you type THREE. in VSCode.

Actual behavior: Compiler doesn't understand typeRoots at all.

error TS2688: Cannot find type definition file for 'three'.

Also VSCode treats THREE as any and doesn't offer suggestions like AmbientLight and others.

As I said, several of confused questions on Stackoverflow, with general answer reciting scarce TypeScript/tsconfig docs on the typeRoots:

If typeRoots is specified, only packages under typeRoots will be included. For example:

 {
    "compilerOptions": {
        "typeRoots" : ["./typings"]
    }
 }

You can see, I used the same syntax, to the point of leading ./ and lack of trailing /.

Quite possibly some other intricate (or obvious??) detail is missed on my part. In that case what would help A LOT is one small thing: a simple reproduction example where typeRoots works as expected.

I can see there are couple dozen tests exercising @typeRoots with harness virtualized file system, but would be good to have it clean and reproduceable with just tsc. Thanks!

mattmccutchen commented 6 years ago

I can't reproduce the problem. Use the --traceResolution flag to get more information, and if you still can't fix the problem, please ask on Stack Overflow and we can troubleshoot there.

RyanCavanaugh commented 6 years ago

We'd need at minimum a sample repo for this, since we can't see what the filenames are, what the file contents are, whether there are package.json files, etc.

mihailik commented 6 years ago

I've created a trivial reproduction repository:

https://github.com/mihailik/typeRoots

I've reproduced it on:

Should be pretty easy to check and hope you can point out the issue easily.

If it's a misconfiguration on my side, it would be awesome to have a similarly trivial sample case, but working. The typeRoots official docs are vague, no sample either. Let's help people use typeRoots correctly!

Thanks @RyanCavanaugh @mattmccutchen

mattmccutchen commented 6 years ago

@mihailik You should be using baseUrl/paths, not typeRoots, in this case. See this Stack Overflow answer.

This seems to be a very common misconception and we should see if we can improve the documentation.

mihailik commented 6 years ago

Thanks @mattmccutchen — follow-ups:

  1. Do we need to include "baseUrl": "." or can it be omitted as default?
  2. What would be the actual syntax for "path" in my case above? I'm confused whether to refer to "three" or "@types/three".

With that I can update the repo, and make it a definite working sample for other people to look at. Thanks!

mattmccutchen commented 6 years ago
  1. FBOFW, baseUrl is required when paths is specified.
  2. The key should be "three" because that's what's being imported. It's a good enough overview for present purposes that when you import ... from "foo", TypeScript checks for a declaration file in (a) any specified paths for foo, (b) node_modules/foo, and (c) node_modules/@types/foo in that order. Given that you can never import ... from "@types/foo", a paths setting for @types/foo will never be used.

So the tsconfig.json in your example would be:

{
   "compilerOptions": {
       "lib": ["es6", "dom"],
       "baseUrl": ".",
       "paths": {
         "three": ["customtypings/node_modules/@types/three"]
       },
       "strict" : true
   }
}
darkmastermindz commented 5 years ago

@mihailik Did you get it working?

mihailik commented 5 years ago

Yes, I did @darkmastermindz — following @mattmccutchen example.

Thanks a lot, by the way! 👍

mihailik commented 5 years ago

Could be super-useful to put in docs too!