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 examples don't compile #1455

Closed
lf- opened this issue Oct 19, 2019 · 12 comments
Closed

TypeScript examples don't compile #1455

lf- opened this issue Oct 19, 2019 · 12 comments

Comments

@lf-
Copy link

lf- commented Oct 19, 2019

Hi! I've been converting a project to use Yargs recently and was having some issues with the compiler being dissatisfied with my program, so I tried one of the examples in docs/typescript.md to see if I could better understand the issue.

Unfortunately, it seems to have the same problem as my code was having:

test.ts:4:20 - error TS2339: Property 'options' does not exist on type '{ <K extends never, V>(key: K, value: V, description?: string): Argv<Omit<{}, K> & { [key in K]: V; }>; <K extends string, V>(key: K, value: V, description?: string): Argv<{ [key in K]: V; }>; <D extends { [key: string]: any; }>(defaults: D, description?: string): Argv<...>; }'.

4 const argv = yargs.options({
                     ~~~~~~~

It appears that the compiler is possibly not seeing whatever object results from import yargs from 'yargs' as an instance of Argv, which seems very strange indeed. How should we fix the examples so they compile, or fix the definitions so they work with the examples?

Contents of test.ts:

#!/usr/bin/env node
import yargs from 'yargs';

const argv = yargs.options({
  a: { type: 'boolean', default: false },
  b: { type: 'string', demandOption: true },
  c: { type: 'number', alias: 'chill' },
  d: { type: 'array' },
  e: { type: 'count' },
  f: { choices: ['1', '2', '3'] }
}).argv;

Versions:

  "dependencies": {
    "yargs": "^14.2.0"
  },
  "devDependencies": {
    "@types/node": "^12.11.1",
    "@types/yargs": "^13.0.3",
    "typescript": "^3.6.4"
  },
@lf-
Copy link
Author

lf- commented Oct 19, 2019

It is notable that using const yargs = require('yargs') results in this working properly. So there is something wrong with importing it like a module. Although I could submit a pull request to blindly change the docs to the older import syntax, I think this presents an opportunity to better understand how the modules system works and why it is producing this result. Does anyone know why this seems to happen only when importing as a module?

@lf-
Copy link
Author

lf- commented Oct 19, 2019

Aha!

import * as yargs from 'yargs';

results in proper types working. Is this a code smell or should I just file a pull request on the docs to change them to this syntax? (again, I don't know about the conventions around modules in TS)

@mantysalo
Copy link

I think it depends on your tsconfig.

If you have esModuleInterop set to true it works fine with import yargs from 'yargs'

@bcoe
Copy link
Member

bcoe commented Oct 22, 2019

👋 any thoughts on whether we should suggest using esModuleInterop in the docs, or whether we should instead change our sample?

@bcoe bcoe added the question label Oct 22, 2019
@lf-
Copy link
Author

lf- commented Oct 22, 2019

That is a fantastic question. I think we should probably suggest using esModuleInterop since that results in the code being compliant with the ES modules spec which might imply it's more "best practice" (assuming I read the Stack Overflow answer about this correctly).

But I'm not a JavaScript developer and don't know enough about the context here to make that decision. Still I could write up a pull request of this and see what others think.

@bcoe
Copy link
Member

bcoe commented Oct 22, 2019

perhaps this just means that we should update the docs to call out this configuration.

@giacomocerquone
Copy link

giacomocerquone commented Nov 6, 2019

Actually, through this, I solved another error! I wasn't able to type argv correctly and typescript was complaining about the non-matching property types. Solved using require but I had already defined esModuleInterop: true

I'm typing it like this:

interface Arguments {
  _: any;
  gradlePath: string;
  iosPath: string;
  bldSettings: string;
}

const argv: Arguments = yargs.options({
  bldSettings: { type: "string" },
  gradlePath: { type: "string" },
  iosPath: { type: "string" }
}).argv;

In particular, this was the error

index.ts:13:7 - error TS2322: Type '{ [x: string]: unknown; bldSettings: string | undefined; gradlePath: string | undefined; iosPath: string | undefined; _: string[]; $0: string; }' is not assignable to type 'Arguments'.
  Types of property 'gradlePath' are incompatible.
    Type 'string | undefined' is not assignable to type 'string'.
      Type 'undefined' is not assignable to type 'string'.

13 const argv: Arguments = yargs.options({

UPDATE:

import * as yargs from 'yargs' doesn't solve my problem

@bcoe bcoe added the p1 label Nov 6, 2019
@bcoe
Copy link
Member

bcoe commented Nov 6, 2019

@giacomocerquone in this example, bldSettings, etc., are not required arguments so can be string|undefined.

I think this is a different issue; once you get things working, I would happily accept an update to the TypeScript example; I think we should probably avoid esModuleInterop ideally.

@giacomocerquone
Copy link

Ok but why does it disappear when using require instead of import?

@bcoe
Copy link
Member

bcoe commented Nov 6, 2019

@giacomocerquone I believe require doesn't pull in all the types right? so it's not enforcing the Types.

@Jack-Barry
Copy link

I have esModuleInterop set to true, and this wasn't working for me with

import yargs from 'yargs'
// or
import * as yargs from 'yargs'

and require feels icky because there's just no type checking at all. However, this workaround does what I need it to:

((yargs() as unknown) as Argv<{}>) // Chain your method calls here

Not the cleanest syntax but it's a pretty safe coercion and allows type checking to work correctly.

@mleguen
Copy link
Member

mleguen commented Dec 18, 2019

@Jack-Barry Please have a look at the doc fix in #1513 (not merged yet).

You should use import yargs = require("yargs");.

@bcoe bcoe closed this as completed Dec 22, 2019
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

6 participants