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.
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.
IntelliSense# Visual Studio Code's JavaScript IntelliSense provides intelligent code completion, parameter info, references search, and many other advanced language features.
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.
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.
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 ).
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).
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With