Importing withStyles from @material-ui/styles/withStyles is returning a typescript error.
No typescript error
Could not find a declaration file for module '@material-ui/styles/withStyles'. '/Users/vlanglet/Project/cloud/front/node_modules/@material-ui/styles/withStyles.js' implicitly has an 'any' type.
Try `npm install @types/material-ui__styles` if it exists or add a new declaration (.d.ts) file containing `declare module '@material-ui/styles/withStyles';`
5 import withStyles, { StyleRules, WithStyles } from '@material-ui/styles/withStyles';
import withStyles, { StyleRules, WithStyles } from '@material-ui/styles/withStyles';
The following lines return no error but I was expected to import everything from @material-ui/styles/withStyles
import { withStyles } from '@material-ui/styles';
import { StyleRules, WithStyles } from '@material-ui/styles/withStyles';
I assume it's the same problem for others modules.
| Tech | Version |
|--------------|---------|
| Material-UI | v3.9.1 |
| TypeScript | v3.2.2 |
I cannot reproduce this with @material-ui/[email protected]: https://codesandbox.io/s/pk1noowqk0 (need to start locally since codesandbox has not typechecking for mui)
Please add your @material-ui/styles version, tsconfig.json and where this error is displayed (IDE, tsc etc)
That your second example is working hints to an issue with your tsconfig or a typescript bug. At least the error message is misleading since the declaration obviously exists. TS just can't find it if you're using default and named imports.
@eps1lon I used last @material-ui/styles, the error is displayed in both Phpstorm and with tsc.
This is my tsconfig.json:
{
"compilerOptions": {
"target": "es6",
"jsx": "preserve",
"allowJs": true,
"noEmit": true,
"pretty": true,
"skipLibCheck": false,
"alwaysStrict": true,
"noImplicitAny": true,
"suppressImplicitAnyIndexErrors": true,
"noImplicitThis": true,
"strict": true,
"strictFunctionTypes": true,
"strictNullChecks": true,
"strictPropertyInitialization": true,
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"isolatedModules": true,
"lib": ["dom", "dom.iterable", "esnext"],
"types": ["node", "jest"]
},
"include": ["src"]
}
With that tsconfig I can only reproduce #14297. Once I resolve this everything works fine.
I assume with latest you mean @material-ui/[email protected].
I agree, I can't reproduce this with your project and my tsconfig.json.
But I still have this error with my project. I don't know why. I'll looking for a diff.
It's a work project so I can't push it to github ; but I'll try to make a minimal project with this error.
@eps1lon
git clone [email protected]:VincentLanglet/MaterialTest.git
cd MaterialTest
yarn
yarn tsc
I'm having the same problem when using something from @material-ui/styles.
and can reproduce even with the freshly install app
here's how to reproduce
create-react-app reproduce-with-styles-type --scripts-version=react-scripts-ts
cd reproduce-with-styles-type
yarn add @material-ui/styles @material-ui/icons @material-ui/core
yarn start
everything works fine unless we add the import statement in App.tsx
// App.tsx
import * as React from 'react'
import './App.css'
import withStyles from '@material-ui/styles/withStyles' // <-- Here
import logo from './logo.svg'
now typescript will complain about not having the type definition file for material-ui__styles
so here is how I fixed it
index.tsximport '@material-ui/styles' on top of file.import '@material-ui/styles' // <-- Here
import * as React from 'react'
import * as ReactDOM from 'react-dom'
and typescript will stop complaining.
and for the version of package according to package.json
{
"dependencies": {
"@material-ui/core": "^3.9.1",
"@material-ui/icons": "^3.0.2",
"@material-ui/styles": "^3.0.0-alpha.9",
"react": "^16.7.0",
"react-dom": "^16.7.0",
"react-scripts-ts": "3.1.0"
},
"devDependencies": {
"@types/jest": "^23.3.13",
"@types/node": "^10.12.20",
"@types/react": "^16.7.22",
"@types/react-dom": "^16.0.11",
"typescript": "^3.2.4"
}
}
I understand what's happening now. We're declaring the @material-ui/styles/withStyles module in @material-ui/styles/index.d.ts. But if you only ever import from @material-ui/styles/* typescript never touches the index.d.ts where the modules are declared.
In a perfect world typescript would fallback to index.d.ts but I understand that this is very opinionated about how typescript acquires types. This is also potentially an issue for us if we ever want to flatten the module declarations in @material-ui/core.
I would recommend you use named imports from the index. If you're concerned with bundle size then you should fix this in your bundler. @material-ui/styles is "tree-shake-viable".
If this is not possible you force typescript to read the index.d.ts by simply importing a type e.g. import { WithStyles } from "@material-ui/styles"; This will never affect your bundle size.
I tried adding node_modules/@material-ui/styles to the typeRoots but then typescript complains because the nested node_modules contains no type declarations.
Personally I wouldn't use path imports and just use named imports. Especially since it prevents you from using private members such as StylesRules
@eps1lon The bundle size is a real issue, and it shouldn't require config in our bundler. I use create-react-app, I don't want to eject for this.
I have no issue with @material-ui/core/styles which is a submodule of @material-ui/core.
And some librairies like lodash works really well with submodule and typescript.
There is clearly something we can do about this with material ui.
PS : And I do use StylesRules and it's quite helpful this way to type return type.
type ClassKey = 'appBar' | 'toolbar';
const styles = (theme: Theme): StyleRules<ClassKey> => ({
appBar: {
zIndex: theme.zIndex.drawer + 1,
},
toolbar: theme.mixins.toolbar,
});
export default withStyles(styles)(NavBar);
@eps1lon The bundle size is a real issue, and it shouldn't require config in our bundler. I use
create-react-app, I don't want to eject for this.
Yes this is what es modules are for. Unless you are on some very old setup using the named import should be equivalent to the path import.
There is clearly something we can do about this with material ui.
Yes we could "deflatten" the module like we do for the core. However this not only makes our current architecture harder to navigate it also has implications on things like codesandbox that bail out of type aquisition if it encounters to many files. Essentially you're asking to support a pattern that is only valueable for old build pipelines in an alpha module that requires the latest react version
PS : And I do use
StylesRulesand it's quite helpful this way to type return type.
We have createStyles for that purpose. Our typescript guide explains the usage: https://material-ui.com/guides/typescript/. StyleRules is an private type that could be refactored and break your build anytime.
We have
createStylesfor that purpose. Our typescript guide explains the usage: https://material-ui.com/guides/typescript/.StyleRulesis an private type that could be refactored and break your build anytime.
The type def rules of tslint check return types of function.
(theme) => createStyles({})
should be
(theme: Theme): ReturnType => createStyles({})
That's why I think StyleRules useful
should be
(theme: Theme): ReturnType => createStyles({})That's why I think StyleRules useful
Good point. createStyles helps with deduplication of class keys which is a good argument for not using the explicit type annotation here. Since it's both an argument for withStyles and the return type of createStyles I think we should probably consider it part of the public API anyway.
Feel free to open a PR that re-exports this type in index.d.ts. This would enable you to only use path imports.
@eps1lon Like this ? https://github.com/mui-org/material-ui/pull/14362
@VincentLanglet Just remember that StyleRules<ClassKey> is not accepted in @material-ui/styles. You have to add the props type.
Yes good catch, I didn't see the difference between the one from @material-ui/core/styles and this one.
@VincentLanglet Could you try adding "types": ["@material-ui/styles"] to compilerOptions in your tsconfig? This solved this issue for me. It might however hurt with other type aquisitions.
@eps1lon I think again about this issue.
Why does index.d.ts declare all the modules types and you not kept the way you did on material-ui/core with a withTheme.d.ts file, a withStyles.d.ts file, etc... ?
I can do it if you want.
Why does index.d.ts declare all the modules types and you not kept the way you did on material-ui/core with a withTheme.d.ts file, a withStyles.d.ts file, etc... ?
Simply because clutter. @oliviertassinari didn't want to use the same folder architecture we use for the core. I wanted to use it simply to cleanup the files so that tests and implementation are isolated from one another. If we add interface i.e. type declarations in the mix the sheer number of files makes it unmanageable.
@eps1lon I'm happy to change it. I was wondering the same. It would probably help with https://github.com/mui-org/material-ui/issues/14808#issuecomment-471229471.
@oliviertassinari Do you want to split the index.d.ts file ? I can help
I'm in favor of splitting index.d.ts, @eps1lon does it sound good to you?
I'm in favor of splitting
index.d.ts, @eps1lon does it sound good to you?
If we use the same folder architecture as /core. I'm uncomfortable with it otherwise since navigating in a 50+ files folder is cumbersome.
It wont be bigger than the @material-ui/core/styles folder ; where files are splitted.
But it's possible to do something like
--createGenerateClassName
----index.js
----index.d.ts
----createGenerateClassName.js
----createGenerateClassName.d.ts
----createGenerateClassName.test.js
--createStyles
----...
...
Do you want me to create the PR ?
@VincentLanglet This proposal sounds good to me. It makes us follow the core & lab strategy. It's allowing the introducing of multiple package.json file to solve the esm/cjs duplication issue. @eps1lon So yes, we can go for consistency between core, styles & lab :).
Working on it: https://github.com/mui-org/material-ui/pull/14868