1

I'm writing JS with a jsconfig.json in order to provide extra TS type checking.

The issue is that the TS language server doesn't seem to be smart enough or equipped to handle such situations. I get the following error:

Types of property 'mode' are incompatible.
    Type 'string' is not assignable to type '"production" | "development"'.

for the following code:

return {
  ...
  mode: isProd ? 'production' : 'development',
}

I completely understand why this is an error and how to solve it in TS (see https://stackoverflow.com/a/37978675/15388164), but in JS, we don't have type or const assertions.

Is there a good way to deal with this? I use this config in half a dozen spots, so I don't want to //@ts-ignore every site. If anything, I'd like to disable these 'string is not assignable to other strings' issues altogether as they provide no value in JS as far as I can see. The types will always be inferred incorrectly.

rschristian
  • 1,730
  • 1
  • 6
  • 15

1 Answers1

2

Weird - what version of TypeScript are you using? TypeScript is generally pretty good about inferring types, even from vanilla JS files. You might have some kind tsconfig error somewhere - maybe post more of your config info so we could have a look.

Another option is to use JSDoc annotations in your JS files. JSDoc is pretty awesome for this purpose and plays very nicely with TypeScript. You can use an inline @type annotation to directly define the type for a specific field of your return object [Edit: better solution below this one]:

return {
    /**
     * @type {"production" | "development"}
     */
    mode: isProd ? "production" : "development",
}

Edit: after playing around in codesandbox.io a bit, it seems that TypeScript does not infer object property types very well - it generally works best when inferring basic variable values and function returns etc. (This makes sense if you think about it - an object property value can easily change to something else and can not be assumed to be constant, whereas a basic variable declaration that is declared as const foo = "myString" is pretty much guaranteed to always be "myString")

Probably a better option than the one above would be to import the Webpack configuration type into your JS files via JSDoc and use it to type your config object directly. Something like this:

/**
 * @param {boolean} isProd
 * @returns {import('webpack').Configuration}
 */
export function getConfig(isProd) {
  return {
    mode: isProd ? "production" : "development"
  };
}

This has the awesome benefit of TypeScript actually checking the proper types of your Webpack config fields directly in your vanilla JavaScript file, in addition to playing nicely when you utilize that config object in TypeScript files.

jered
  • 11,220
  • 2
  • 23
  • 34
  • Yeah like I said, I totally get why this is the case and how to solve it in a TS context, but JS is the issue. This isn't related to Webpack in any way, though I guess the type looks similar and is why you assumed that? Unfortunately there's no type to import and use in JSDoc here (giant inline type for function parameters), and there's like 3 dozen keys on the object, so... not writing a typedef for the whole thing. Oh well. – rschristian Jan 30 '22 at 02:16
  • @rschristian ah I did assume webpack. I’m surprised there is no type you can import, but at least you can solve it with the inline property type definition mentioned in my answer. – jered Jan 30 '22 at 05:30
  • The first snippet? That's what I had tried before posting this but couldn't get it to work correctly, Maybe I have another issue on top of this, I'm thinking an `Object.assign` somewhere that might "erase" that type definition. Will have to look into it more, if it should be working that's good news, and a totally workable solution. – rschristian Jan 30 '22 at 05:45
  • Coming back to this super late, but the first suggestion does work in some contexts, so I thought I'd mark it as the answer. The type annotation does seem to "get lost" quite easily so you cannot do much in the way of manipulation, but for static objects, it does work pretty well. – rschristian Apr 16 '22 at 04:39