Roll in style.
Highly opinionated configuration files for typescript projects.
Tip
Let your agent set this up for you:
Read https://raw.githubusercontent.com/TimoBechtel/style/main/skills/setup-style/SKILL.md and configure.
Make sure to first commit your code before running the following commands. This allows you to revert changes easily.
npm i -D @timobechtel/style typescriptInstall gh-get to make it easier to download the template files:
gh extension install timobechtel/gh-getCode formatter, replaces Prettier.
npm i -D oxfmtgh get timobechtel/style templates/.oxfmtrc.jsonFaster ESLint alternative. 5x faster in personal testing.
npm i -D oxlintCore:
gh get timobechtel/style templates/.oxlintrc.jsoncReact:
gh get timobechtel/style templates/react/.oxlintrc.jsoncMigrating to Oxlint? - `File '@timobechtel/style/tsconfig/core' not found.`
When migrating from ESLint to Oxlint, you might need to update the tsconfig.json file:
- "extends": ["@timobechtel/style/tsconfig/core"]
+ "extends": ["@timobechtel/style/tsconfig/core.json"]- "extends": ["@timobechtel/style/tsconfig/react"]
+ "extends": ["@timobechtel/style/tsconfig/react.json"]tsgolint requires a file extension to resolve the config file.
Pre-configured tsconfig files.
For existing projects or templates, I recomment leaving the config as-is and adding this preset to the extends array.
{
"extends": ["@timobechtel/style/tsconfig/core.json"]
}gh get timobechtel/style templates/tsconfig.jsongh get timobechtel/style templates/react/tsconfig.jsonOr manually
Copy to tsconfig.json:
{
"extends": "@timobechtel/style/tsconfig/react.json"
}With expo make sure to add "moduleResolution": "bundler" to the compilerOptions, otherwise certain routing types might break.
Example
Copy to tsconfig.json:
{
"extends": ["expo/tsconfig.base", "@timobechtel/style/tsconfig/core.json"],
"compilerOptions": {
"moduleResolution": "bundler", // <-- this is important
"strict": true,
"paths": {
"@/*": ["./*"]
}
},
"include": ["**/*.ts", "**/*.tsx", ".expo/types/**/*.ts", "expo-env.d.ts"]
}Prettier config will not be updated anymore. I recommend using Oxfmt instead. oxfmt has been configured to match prettier rules, however this might drift in future versions.
Setup prettier anyways
npm i -D prettiergh get timobechtel/style templates/.prettierrcExtend / customize config
Need to extend the config, e.g. adding plugins?
gh get timobechtel/style templates/.prettierrc.mjsCreate a .prettierrc.mjs file and import the config, like this:
import config from '@timobechtel/style/prettier/index.mjs';
/**
* @type {import("prettier").Config}
*/
export default {
...config,
// your config
};Eslint config will be removed in a future version. Use Oxlint instead. oxlint has been configured to match existing eslint rules, however this might drift in future versions.
Setup eslint anyways
npm i -D eslintgh get timobechtel/style templates/eslint.config.jsNote: If your project is not ESM (no "type": "module" in package.json), rename the file to eslint.config.mjs.
Or manually
Copy the following to an eslint.config.js:
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { defineConfig } from 'eslint/config';
import styleCore from '@timobechtel/style/eslint/core.js';
import { createTypeScriptImportResolver } from 'eslint-import-resolver-typescript';
import { createNodeResolver } from 'eslint-plugin-import-x';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
export default defineConfig([
...styleCore,
{
languageOptions: {
parserOptions: {
tsconfigRootDir: __dirname,
},
},
settings: {
'import-x/resolver-next': [
createTypeScriptImportResolver({
project: path.resolve(__dirname, 'tsconfig.json'),
}),
createNodeResolver(),
],
},
},
]);gh get timobechtel/style templates/react/eslint.config.jsOr manually
Also spread styleReact from @timobechtel/style/eslint/react.js:
import styleCore from '@timobechtel/style/eslint/core.js';
import styleReact from '@timobechtel/style/eslint/react.js';
import { defineConfig } from 'eslint/config';
export default defineConfig([
...styleCore,
...styleReact,
// ... your config
]);If you're upgrading from v1.x, you'll need to:
- Upgrade to ESLint v9+
- Replace
.eslintrc.cjswitheslint.config.js - Update imports to use
.jsextension (e.g.,@timobechtel/style/eslint/core.js) - Note: Import plugin rules now use
import-x/prefix instead ofimport/
Note: You should disable source.organizeImports in your VSCode config, as this collides with the import-x/order rule.
Add the following to your VSCode config, e.g. .vscode/settings.json
{
"editor.codeActionsOnSave": {
// use eslint import-x/order instead
"source.sortImports": "never"
}
}This repo also contains a semantic-release configuration.
npm i -D semantic-release @semantic-release/changelog @semantic-release/gitgh get timobechtel/style templates/.releaserc.jsonnpx skills add timobechtel/style@setup-style