Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TypeScript] "error TS2304: Cannot find name 'moment'" when used with "module":"none" #3763

Closed
rossipedia opened this issue Feb 14, 2017 · 53 comments

Comments

@rossipedia
Copy link

Typescript seems to not be able to resolve the global moment() function when used in a non-module context.

tsc version: 2.1.6
moment version: 2.17.1

Repro (assuming tsc is on your $PATH):

$ mkdir repro && cd repro
$ npm i moment
$ echo 'const now = moment();' > test.ts
$ tsc --module none test.ts
test.ts(1,13): error TS2304: Cannot find name 'moment'.

However, using a module type works as expected:

$ echo 'import * as moment from "moment"; const now = moment();' > test2.ts
$ tsc --module commonjs test2.js

Unfortunately, my project does not use a bundler or module system, so I'm stuck with "module": "none" for now.

Is my only alternative to use something like typings install --save --global dt~moment ?

@alexdresko
Copy link

I'm facing the same problem. It doesn't matter what module type you specify in tsconfig.json. I get the same error as @rossipedia

@VolodymyrBaydalka
Copy link

VolodymyrBaydalka commented Feb 20, 2017

I reported same issue (#3663), but unfortunately it was just closed without any reaction.

@alexdresko
Copy link

I ended up copying moment.d.ts into my /scripts/app directory and implemented the fix specified in #3663 (comment)

Hopefully a more permanent fix will make its way into moment.d.ts eventually.

@kamek-pf
Copy link

I solved this by specifying "moduleResolution": "node" in my tsconfig. Not sure if this is an option for you guys, but it seems to do the trick.

@rossipedia
Copy link
Author

"moduleResolution": "node" did not fix it for me, unfortunately

@alexdresko
Copy link

@rossipedia Me either.

@oldrich-s
Copy link

oldrich-s commented Mar 5, 2017

Would it not help to add export as namespace moment; into the moment.d.ts file?

See: #3808

@rossipedia
Copy link
Author

@czb that also did not fix the issue for me, unfortunately :(

@mtgibbs
Copy link

mtgibbs commented Mar 23, 2017

I've resolved this using a couple of hacks that others have mentioned around a ton of issues in lots of projects that are having this problem. Just wrap it up in a custom definition file of your own. This is using Typescript 2.2. This way I'm not mucking with the dependency coming down from npmjs.org and I don't have to check the whole thing into source control.

tsconfig.json

"compilerOptions": {
    "target": "ES5",
    "moduleResolution": "node",
    ...
}

moment.custom.d.ts

import * as _moment from 'moment';
export as namespace moment;
export = _moment;

@rossipedia
Copy link
Author

I'm curious as to why that doesn't work when that code is added directly to moment.d.ts? I can't help but think we're butting into some obscure TypeScript resolution bug, and unfortunately tsc doesn't have a verbose mode (that I know of) that would help pinpoint where things are going wrong.

@oldrich-s
Copy link

I think that if you define "module": "none" typescript does not look for d.ts files under the node_modules/moment folder. My experience is that it is only looking under the node_modules/@types folder. So there are basically these options.

  1. Copy moment.d.ts under node_modules/@types/moment
  2. Include /// <reference path="./node_modules/moment/moment.d.ts" /> into your .ts file
  3. Call tsc --typeRoots node_modules test.ts
  4. Put the ./node_modules/moment/moment.d.ts into files section of tsconfig.json

You also need to add export as namespace moment; into the moment.d.ts file.

@marwahaha
Copy link
Member

the Moment team would love any PRs that would fix this, but stay TS 1.x compatible.

@rossipedia
Copy link
Author

I still have yet to find a solution that works at all, but when I do I'll be sure to add a PR

@cg-cnu
Copy link

cg-cnu commented Apr 4, 2017

According to #3663 the temporary fix to get it working without any bundler...

  • Copy moment.d.ts from node_modules/moment/ to node_modules/@types/moment

  • Change export = moment; in moment.d.ts to

declare module "moment" {
    export = moment;
}
  • Rename moment.d.ts to index.d.ts

Just use moment and your editor( in my case vscode ) and tsc shouldn't complain

@evanjmg
Copy link

evanjmg commented Apr 18, 2017

+1 please fix this

@elSteeze
Copy link

elSteeze commented Jun 6, 2017

@mtgibbs Where are you putting the moment.custom.d.ts file? Is there any other configuration that needs to happen for your app to find this custom.d.ts file?

@mtgibbs
Copy link

mtgibbs commented Jun 6, 2017

@elSteeze

Yeah, I'm adding them to my tsconfig.json. Here's a scrubbed example:

{
  "compilerOptions": {
    "target": "ES5",
    "moduleResolution": "node",
    "typeRoots": [
      "./node_modules/@types"
    ]
  },
  "compileOnSave": true,
  "exclude": [
    "node_modules",
    "./path/to/typings/**/*.d.ts",
    "./typings"
  ],
  "include": [
    "./path/to/typings/moment.custom.d.ts",
    "./path/to/src/**/*.ts"
  ]
}

@elSteeze
Copy link

elSteeze commented Jun 6, 2017

@mtgibbs Hey thanks man! Appreciate the speedy reply. I'll give that a try.

@elSteeze
Copy link

elSteeze commented Jun 6, 2017

@mtgibbs Sorry for another noob like question, after implementing your solution I started getting editor errors on the moment keyword in my ts code...

'moment' refers to a UMD global, but the current file is a module. Consider adding an import instead

I did some personal research and attempted to implement a solution by rewriting moment.custom.d.ts but unfortunately, that didn't fix my issue.

Sorry, not trying to be one of those pesky dev's who makes everyone else debug their code, I'm a recent grad and I'm new to working with 3rd party libraries in an Angular 2 environment

Here is my updated module.custom.d.ts

declare var moment: any;
declare var module: NodeModule;
interface NodeModule {
    id: string;
}
import * as _moment from 'moment';
export as namespace moment;
export = _moment;

@mtgibbs
Copy link

mtgibbs commented Jun 6, 2017

No problem. If you're using Angular 2 you should be on 2.0+ TS. I don't work in Angular so I'm unsure. Mind pasting what you can of your tsconfig.json and I'll take a look after I get back to a real computer.

@elSteeze
Copy link

elSteeze commented Jun 6, 2017

Sure!

This is my entire tsconfig.es5.json file inside the src directory of my angular 2 module I'm building.
I appreciate the help by the way

{
  "compilerOptions": {
    "declaration": true,
    "module": "es2015",
    "target": "es5",
    "baseUrl": ".",
    "stripInternal": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "moduleResolution": "node",
    "outDir": "../build",
    "rootDir": ".",
    "lib": [
      "es2015",
      "dom"
    ],
    "skipLibCheck": true,
    "typeRoots": [
      "./node_modules/@types"
    ]
  },
  "compileOnSave": true,
  "exclude": [
    "node_modules",
    "./typings/**/*.d.ts",
    "./typings"
  ],
  "include": [
    "./typings/moment.custom.d.ts",
    "./src/**/*.ts"
  ],
  "angularCompilerOptions": {
    "annotateForClosureCompiler": true,
    "strictMetadataEmit": true,
    "skipTemplateCodegen": true,
    "flatModuleOutFile": "new-version-library.js",
    "flatModuleId": "new-version-library"
  },
  "files": [
    "./index.ts"
  ]
}

@mtgibbs
Copy link

mtgibbs commented Jun 6, 2017

What version of TS are you compiling in? You should just be able to import moment at the top without my hack.

@elSteeze
Copy link

elSteeze commented Jun 7, 2017

@mtgibbs I'm using v2.2, and that's what I thought. Unfortunately, it's not working. I'm almost at the point where I write my own version of the functionality we're taking from momentjs, because I can't seem to get this working.

@mtgibbs
Copy link

mtgibbs commented Jun 7, 2017

@elSteeze

Ok, going back here. I noticed that you said that you've made a custom module.custom.d.ts, but then you refer to my moment.custom.d.ts in your tsconfig.json. Make sure that you've made moment.custom.d.ts and added it to your compiler, none of that extra stuff that you had declaring it things. Then make sure that you're referencing it at the top of the file you're wanting to use it in.

/// <reference path="path/to/your/moment.custom.d.ts" />

This should allow you to reference it as a global variable like in my original workaround.

@elSteeze
Copy link

elSteeze commented Jun 7, 2017

Awesome thank you @mtgibbs ! I really do appreciate the help.
I altered my file structure to support your paths. So those are correct paths.
Cheers mate!

@ShawnTalbert
Copy link

ShawnTalbert commented Jun 23, 2017

This works for me:

  • comment out // export = moment in the official moment.d.ts file
  • add node_modules/moment/moment.d.ts to tsconfig.json

Alternately, copy the modified moment.d.ts to a location of your choice and add the path to it in your tsconfig.json

I think the main problem is that when explicitly using "module":"none" in tsconfig.json you can't have any top level import or exports in any libraries (because you're then using modules).

@gyanchandk
Copy link

you have to first import in component as
import * as moment from "moment";

it worked well for me

@valeriob
Copy link

you have to first import in component as
import * as moment from "moment";
it worked well for me

If you do that in a file, then namespace resolution is disabled for that files.

Pls guys +1 to fix this

@darek8686
Copy link

Why don't you fix this issue? It is very important.

@AmirTugi
Copy link

AmirTugi commented May 24, 2018

Adding "module": "commonjs" to the tsconfig.json fixed it for me

@darek8686
Copy link

But i have to use "module": "none". Commonjs is not a solution.

@rossipedia
Copy link
Author

If I'm understanding it correctly, this will be resolved with TypeScript 2.9's import types feature, which will allow importing type definitions without affecting the the module / ambient context.

@Ciantic
Copy link

Ciantic commented Aug 31, 2018

I'm using TS 3.0.1, is this now solved? It doesn't work out of the box at least.

EDIT, With TS 3.0.1 I could do just this:

declare var moment: typeof import("moment");

Hurray!

With tsconfig

{
    "compilerOptions": {
        "module": "none"
        "moduleResolution": "node", 
        // ...
    }
}

@rossipedia
Copy link
Author

TS 3.0.1 seems to fix this issue (and it's been open for over a year and a half with no traction)

@njaineworkplaceapps
Copy link

Hi rossipedia,
I am facing same issue in angular-6 project. As per your comments it's resolved in TS 3.0.1 but angular6 CLI doesn't support TypeScript version 3.0.1.

Can you please help to resolve this issue?

@RudeySH
Copy link

RudeySH commented Nov 27, 2018

Did anyone else also encounter the @types/moment npm package which is just a stub and tells you to use the file that's provided by the normal moment package?

... Why does moment have to do it differently compared to every other package? This is the reason why this issue exists, and thousands of hours were spent by developers struggling with this.

Sure, @Ciantic's solution works in TS 3.0.1, but I don't have to use something like declare var moment: typeof import("moment"); for any of the other packages I'm using.

@VolodymyrBaydalka
Copy link

It doesn't look like Typescript 3.0.1 fix that issue, it looks like it just give us workaround.

@RudeySH
Copy link

RudeySH commented Nov 28, 2018

it looks like it just give us workaround.

Yup, it's exactly this. This is not an acceptable "fix".

It's only been a day and I just realized that the TS 3.0.1 workaround only imports the moment function, not the namespace/types. So if you want to pass a moment object into a function, this happens:

image

Please reopen this issue, or better: fix the .d.t.s file.

@pspi
Copy link

pspi commented Feb 16, 2019

Not a solution to the original problem, but for people googling this later: specifying the following in tsconfig.json fixed it (typescript 3.3.3 and moment 2.24.0)

{
  "compilerOptions": {
    "module": "commonjs"
  }
}

@rossipedia
Copy link
Author

I'm no longer using moment for much these days, but I'm happy to re-open the issue if it's still valid.

@rossipedia rossipedia reopened this Feb 18, 2019
@nagipogu
Copy link

ERROR in src/app/services/get-list.service.ts(22,54): error TS2304: Cannot find name '_'.

what is the solution for this??

@i-cant-git
Copy link

@nagipogu No solution for that, this issue is for moment.js, please open your issue in underscore.js's Github repository.

@markcellus
Copy link

I'm running into this issue with latest version of moment with latest version of TS. Does anyone have any successful workaround?

@dko-slapdash
Copy link

Still not working, the solution for me was to yarn add -W moment@2.22.1.

When I installed the latest moment version and looked into node_modules/moment/package.json, I saw this: https://github.com/moment/moment/blob/develop/package.json#L29 - but there was no existing directory node_modules/moment/ts3.1-typings, so it's not surprising TS coudln't find it. I think there may be some bug with an installation script (or a package) or so. Yes, we have "module": "esnext" in tsconfig.json.

@rastenis
Copy link

rastenis commented May 1, 2020

For me it broke with 2.25.0:

I used pnpm add moment@2.24.0 as a temporary workaround.

@anouarattn
Copy link

For me it broke with 2.25.0:

I used pnpm add moment@2.24.0 as a temporary workaround.

work good, thank you

@barryguda-1
Copy link

For me it broke with 2.25.0:

I used pnpm add moment@2.24.0 as a temporary workaround.

Same here added it to : "dependencies" {"moment": "^2.24.0",
}...seems to work thank you.

@joshuakeel
Copy link

Downgrading to 2.24.0 also worked for me. Looks like a regression in 2.25.0.

@marwahaha
Copy link
Member

Does 2.25.3 fix your issues?

There are so many different types of situations where Moment.js is used, let alone TS 1.x, TS 2.x, TS 3.x...
I am hesitant to make changes that break any group of these users.

If you think the documentation can be improved, please post at https://github.com/moment/momentjs.com/

@ralftar
Copy link

ralftar commented May 18, 2020

Does 2.25.3 fix your issues?

Yes.

Rolled back to 2.24.0 when 2.25.1 failed for me in Angular 9. With 2.25.3 it's back on track again.

@marwahaha
Copy link
Member

Ok, great. I will close for now.

Please re-open (or open a new issue) if you still have concerns.

@giovannipds
Copy link

I lost a lot of time trying to solve a type problem and @oldrich-s comment of include was very useful! Thanks very much.

@ashkan-dev-86
Copy link

Would it not help to add export as namespace moment; into the moment.d.ts file?

See: #3808

You shouldn't do that.
Because in case of reinstalling, this will reset to its default.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests