Roaders / ts-command-line-args

A typescript wrapper for command-line-args that allow you to generate config from existing TS interfaces
26 stars 11 forks source link

Issue with optionals: Type 'boolean' is not assignable to type 'true' #2

Closed restyler closed 3 years ago

restyler commented 3 years ago

"typescript": "^4.0.2" "ts-command-line-args": "^1.1.0"

interface IProxyChecker2Arguments {
  text?: string
}
const optionDefinitions2 = {
  text: {
    type: String,
    optional: true
  }
}

const options2 = parse<IProxyChecker2Arguments>(optionDefinitions2)

Produces TS error:

 error TS2345: Argument of type '{ text: { type: StringConstructor; optional: boolean; }; }' is not assignable to parameter of type 'ArgumentConfig<IProxyChecker2Arguments>'.
  Types of property 'text' are incompatible.
    Type '{ type: StringConstructor; optional: boolean; }' is not assignable to type 'PropertyOptions<string | undefined>'.
      Type '{ type: StringConstructor; optional: boolean; }' is not assignable to type '{ optional: true; }'.
        Types of property 'optional' are incompatible.
          Type 'boolean' is not assignable to type 'true'.

Expected result: no TS compilation errors.

Roaders commented 3 years ago

You need to either use the options config directly:

  const options3 = parse<IProxyChecker2Arguments>({
    text: {
      type: String,
      optional: true
    }
  })

Or correctly type the options object:

  const optionDefinitions2: ArgumentConfig<IProxyChecker2Arguments> = {
    text: {
      type: String,
      optional: true
    }
  }

  const options2 = parse<IProxyChecker2Arguments>(optionDefinitions2)
restyler commented 3 years ago

Thank you, it works! Still figuring out the TypeScript features 👍

Roaders commented 3 years ago

The issues was that this:

const optionDefinitions2 = {
  text: {
    type: String,
    optional: true
  }
}

is typed as

type optionDefinitions2 = {
  text: {
    type: (value) => string,
    optional: boolean
  }
}

but the type required by parse is

type optionDefinitions2 = {
  text: {
    type: (value) => string,
    optional: true
  }
}

you could have solved this by typing the boolean as a const (which means it won't change so it will be typed as true)

const optionDefinitions2 = {
  text: {
    type: String,
    optional: true as const
  }
}