Typescript Declaration Files for Local JS Files
Asked Answered
B

1

18

I am trying add typings for our Javascript files at work while we are in the process of converting to Typescript. However, I can not get the declaration files to be recognized.

Here is my file structure

  • js
    • Foo.js
  • typings
    • Foo
      • index.d.ts
  • index.ts
  • package.json
  • tsconfig.json

Foo.js

module.exports = function Foo() {
   return 'Bar';
 };

index.d.ts

export = Foo;

declare function Foo(): string;

index.ts

import Foo = require('./js/Foo')

console.log(Foo());

tsconfig.json

{
  "compilerOptions": {
    "typeRoots": ["./typings"],
    "target": "es5",
    "strict": true,
    "baseUrl": "./",
    "paths": {
      "*": ["typings/*"]
    }
  }
}

package.json

{
  "name": "fail",
  "version": "1.0.0",
  "description": "",
  "main": "index.ts",
  "scripts": {
    "tsc": "tsc"
  },
  "author": "",
  "license": "MIT",
  "dependencies": {
    "typescript": "^3.1.4"
  }
}

Here is repo to reproduce my problem

https://github.com/erisman20/typings_help

Edit: Here is there error I get

error TS7016: Could not find a declaration file for module './js/Foo.js'. '....../js/Foo.js' implicitly has an 'any' type.

Berna answered 30/10, 2018 at 23:15 Comment(0)
W
20

The only ways to provide declarations for a relative import such as './js/Foo' are to actually have the declaration file at the import path (plus .d.ts or /index.d.ts) or to have it virtually at the import path based on your rootDirs option. Neither typeRoots nor baseUrl/paths comes into play in this scenario: baseUrl/paths only affects module resolution for "non-relative" paths, and typeRoots can be used to get TypeScript to load files but does not affect the relationship between import paths and files at all.

The simplest solution would be to put a Foo.d.ts file in the same directory as Foo.js. If you want to keep the typings in a separate directory, then you can add "rootDirs": ["js", "typings"] to tsconfig.json. That change is enough to make your example work for me, though I find it confusing to have corresponding Foo.js and Foo/index.d.ts files and would encourage you to be consistent in your use of subdirectories, i.e., either switch to Foo/index.js on the JavaScript side or switch to Foo.d.ts on the TypeScript side.

Willner answered 31/10, 2018 at 0:48 Comment(2)
what if I add "js/*": ["js/*"] to the paths and reference the js file using import Foo = require('js/Foo') ? Then the rootDirs no longer worksBerna
If you want to require('js/Foo') (which assumes proper configuration of your module loader or bundler), then your paths setting should be "js/*": ["js/*", "typings/*"] so that TypeScript looks at typings/Foo. (You can omit the "js/*" target if you have allowJs disabled or you have declaration files for all of your JavaScript files, because in either of those cases, it would not be used.)Willner

© 2022 - 2024 — McMap. All rights reserved.