css-typed v0.2.2
css-typed
Basic TypeScript declaration generator for CSS files.
Table of contents
Usage
Install
Install the CLI tool as a dev dependency.
npm install --save-dev css-typed
Run
Run css-typed
and pass it a glob targeting your CSS files.
npx css-typed 'src/**/*.css'
This will generate .d.css.ts
files next to the original source files.
Note
A CSS module file with the name
foo.module.css
will emitfoo.module.d.css.ts
.
Configure
Configure TypeScript to allow arbitrary extensions (TS 5+).
{
"compilerOptions": {
"allowArbitraryExtensions": true
}
}
Add *.d.css.ts
to your .gitignore
if appropriate.
echo '*.d.css.ts' >> .gitignore
Options
The following table lists the options css-typed
supports.
Prior to the 1.0
release, these may change often.
CLI option | Description |
---|---|
--dashes | Specifies the convention used for locals. |
Dashes
Inspired by postcss’ localsConvention.
Prior to v1.0
, this option will evolve to more closely match the localsConvention
option.
The --dashes
option changes the style of exported classnames, the exports in your TS.
By default, css-typed
will emit class names as-is if the name represents a valid JS/TS identifier.
Note: The logic for “valid” only checks hyphens (dashes, -
) as of v0.2.2
.
When passed dashes
, it will transform kebab-case
classes (dashed names) to camelCase
.
For example, my-class
becomes myClass
.
Use --dashes
when your bundler or build system supports that transformation.
For example, Vite and Gatsby support this.
Recipes
Run script
To run it as part of your build, you will likely include it as a run script, maybe as codegen
or pretsc
.
{
"scripts": {
"codegen": "css-typed 'src/**/*.css'",
"pretsc": "css-typed 'src/**/*.css'",
"tsc": "tsc"
}
}
Watch
The CLI does not have built-in watch support. Feel free to nodemon or similar.
{
"scripts": {
"codegen": "css-typed 'src/**/*.css'",
"codegen:watch": "nodemon -x 'npm run codegen' -w src -e css"
}
}
Motivation
typescript-plugin-css-modules provides a great IDE experience, but cannot perform build-failing type-checking.
Furthermore, the traditional TypeScript ambient module definition fails the noUncheckedIndexedAccess
strict check and causes issues with typed ESLint rules.
// This does not provide strict typing
declare module "*.module.css" {
const classes: { [key: string]: string };
export default classes; // It also uses default export 😿
}
typed-css-modules and typed-scss-modules exist, but the former does not have recent activity and the latter focuses on SCSS. (My current (2023/2024) interests involve modern CSS only.) Both depend on css-modules-loader-core, which appears abandoned.
Therefore, I wrote my own (very basic) implementation.
Contributing
See CONTRIBUTING.md.
Implementation details
This (very basic) implementation uses glob for file matching and css-tree for CSS parsing.
It extracts CSS classes (ClassSelector
in CSS Tree’s AST) and exports them as string
constants (named exports).
I chose CSS Tree after a brief search because it had a nice API, good documentation, and supported CSS nesting (a requirement for my original use case).