Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to enable TypeScript intellisense in VSCode for a codebase in JavaScript when doing module augmentation for a third-party library?

In a standard create-react-app configuration, there’s a third-party component that I can import when needed:

import { Button } from '@mui/material'

// […]
<Button variant="|"></Button>

The library is fully-typed, so hitting Ctrl+Space in VSCode when the cursor is at | will show me a list of possible string variants that I can use. I could add another variant by creating a local component that wraps the @mui/material/Button:

// LocalComponent.js
import React from 'react'
import { Button } from '@mui/material'

// Do something to actually add a variant called `new`.

export const LocalComponent = React.forwardRef((props, ref) => {
  return (
    <Button ref={ref} {...props}>
      {props.children}
    </Button>
  )
})
// LocalComponent.d.ts
import type { ButtonProps } from '@mui/material'

interface Props extends ButtonProps {
  /** @default 'text' */
  variant?: 'text' | 'outlined' | 'contained' | 'new'
}

export declare function LocalComponent(props: Props): React.FunctionComponent

If I import LocalComponent, I can get intellisense for the new variant, as well as the original Button’s props. The library also has a feature that allows me to create new variants without having to wrap the library’s components, but I’m having problems with intellisense when I use it—even though the new variant is implemented, I see only the original variants. The library exposes an interface specifically for module augmentation, so I should be doing something like this:

declare module '@mui/material/Button' {
  interface ButtonPropsVariantOverrides {
    new: true;
  }
}

ButtonPropsVariantOverrides is supposed to be merged with the variant property of the interface that defines all props for the Button, essentially turning it into variant?: 'text' | 'outlined' | 'contained' | 'new', but it seems that TypeScript doesn’t see this module augmentation. I tried the following setup:

// jsconfig.json
{
  "compilerOptions": {
    "baseUrl": "src",
    "typeRoots": [
      "./src/types", "node_modules/@types"
    ]
  },
  "include": ["src"]
}

Not sure if typeRoots does anything in jsconfig—it’s not listed as an available option of compilerOptions, but since jsconfig is almost tsconfig, I tried it anyway.

.
├── src/
│   └── types/
│       └── @mui/
│           └── material/
│               └── Button/
│                   └── index.d.ts // Contains the module augmentation from above.
└── jsconfig.json

As well as this one:

.
├── src/
│   └── types/
│       └── index.d.ts // Contains the module augmentation from above.
└── jsonfig.json

I also made sure to restart the TS server every time I changed something. Where to put module augmentations in general? Is there anything wrong with how I set up jsconfig.json? Here’s a CodeSandbox of what I’ve just described.

Thank you for your time.

like image 646
awgv Avatar asked Sep 17 '21 15:09

awgv


People also ask

Does TypeScript have IntelliSense?

IntelliSense shows you intelligent code completion, hover information, and signature help so that you can write code more quickly and correctly. VS Code provides IntelliSense for individual TypeScript files as well as TypeScript tsconfig.

What is JavaScript IntelliSense?

IntelliSense# Visual Studio Code's JavaScript IntelliSense provides intelligent code completion, parameter info, references search, and many other advanced language features.

How to enable jQuery IntelliSense in VS Code?

If you type $ there is still nothing. To enable jQuery IntelliSense, we need to add a /// reference instruction to our JavaScript file. For some reasons, VS Code does not update after you type the path so if you are stuck with an error like the following, reopen the file and it should fix it.

Does typescript Intellisense support JSDoc?

JSDoc support. VS Code's TypeScript IntelliSense understands many standard JSDoc annotations, and uses them to show typing information and documentation in suggestions, hover info, and signature help. Keep in mind that when using JSDoc for TypeScript code, you should not include type annotations.

Does Visual Studio Code support TypeScript?

The TypeScript language specification has full details about the language. Visual Studio Code includes TypeScript language support but does not include the TypeScript compiler, tsc. You will need to install the TypeScript compiler either globally or in your workspace to transpile TypeScript source code to JavaScript ( tsc HelloWorld.ts ).

How do I copy type definitions from VS Code to IntelliSense?

Here is the copyable snippet: This basically told VS Code to append the type definitions contained in our tsd.d.ts file to its actual IntelliSense. If you open the tsd.d.ts file you will see a reference to jquery/jquery.d.ts which is our jQuery type definitions file (the file we “installed” earlier).


1 Answers

It seems that when a file with module augmentation doesn’t have import/export statements, you’re defining an ambient module—a shape that does not have an implementation—that you have to import manually where needed. To augment a module and make it globally available, the declaration file should have an import or export statement.

What’s bizarre is that the only thing that matters is for the declaration file to be a module with at least one import/export statement, which could be absolutely anything—if I’m augmenting @mui/material/Button, I don’t have to import '@mui/material/Button' specifically, I could write some useless arbitrary export, like export default true, and TypeScript would recognize the file anyway.

I did a quick test on CodeSandbox to see if the same applies to TypeScript projects—it seemingly does. It worked on CodeSandbox without the typeRoots property in tsconfig.json, but add it in case of problems.

Where to put module augmentations in general? Is there anything wrong with how I set up jsconfig.json?

Module augmentation can be in any folder you like, but that directory (or its ancestor) should be in the jsconfig’s include property, and if its ancestor has already been added to include, there’s no need to list the directory with types separately. Although unnecessary, you might want to separate augmented packages into folders containing index.d.ts—do not name the declaration files differently, or TypeScript will ignore them. Using my question as an example, one option is to put the module augmentation into ./src/types/@mui/Button/index.d.ts. Lastly, the typeRoots property, indeed, does nothing when added to jsconfig.json, so there’s no need to use it.

like image 55
awgv Avatar answered Oct 16 '22 16:10

awgv