Shared ESLint configs for internal Expo projects providing multiple presets for different environments.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Optional enhanced TypeScript linting configuration that utilizes parsed type information for more sophisticated analysis. Provides advanced type-aware rules that can catch complex type-related issues but requires additional setup and may increase linting time.
Advanced TypeScript linting rules that require type information from the TypeScript compiler.
// Traditional ESLint config (.eslintrc.js)
module.exports = {
extends: [
'universe', // or universe/native, universe/web, universe/node
'universe/shared/typescript-analysis'
],
overrides: [
{
files: ['*.ts', '*.tsx', '*.d.ts'],
parserOptions: {
project: './tsconfig.json'
}
}
]
};
// Flat Config (ESLint 9+)
const { defineConfig } = require('eslint/config');
const universeConfig = require('eslint-config-universe/flat/default'); // or /native, /web, /node
const typescriptAnalysisConfig = require('eslint-config-universe/flat/shared/typescript-analysis');
module.exports = defineConfig([
...universeConfig,
{
...typescriptAnalysisConfig,
languageOptions: {
...typescriptAnalysisConfig.languageOptions,
parserOptions: {
project: './tsconfig.json'
}
}
}
]);Configuration Requirements:
parserOptions.project pointing to your tsconfig.jsonUsage Examples:
// Basic TypeScript project with type-aware linting
// .eslintrc.js
module.exports = {
extends: [
'universe',
'universe/shared/typescript-analysis'
],
overrides: [
{
files: ['*.ts', '*.tsx', '*.d.ts'],
parserOptions: {
project: './tsconfig.json'
}
}
]
};
// Multi-package monorepo setup
// .eslintrc.js
module.exports = {
extends: [
'universe/node',
'universe/shared/typescript-analysis'
],
overrides: [
{
files: ['packages/*/src/**/*.ts'],
parserOptions: {
project: ['packages/*/tsconfig.json']
}
}
]
};
// React Native project with type analysis
// .eslintrc.js
module.exports = {
extends: [
'universe/native',
'universe/shared/typescript-analysis'
],
overrides: [
{
files: ['src/**/*.{ts,tsx}'],
parserOptions: {
project: './tsconfig.json'
}
}
]
};// Ensures await is used with Promises
'@typescript-eslint/await-thenable': 'warn'
// Prevents unnecessary awaiting of non-Promise values
'@typescript-eslint/no-unnecessary-type-assertion': 'warn'
// Enforces proper return await usage
'no-return-await': 'off' // Disabled in favor of TypeScript version
'@typescript-eslint/return-await': ['error', 'always']Examples:
// ❌ await-thenable violations
await 42; // Warning: awaiting non-Promise
await 'string'; // Warning: awaiting non-Promise
// ✅ Correct usage
await Promise.resolve(42); // OK: awaiting actual Promise
await fetch('/api/data'); // OK: fetch returns Promise
// ❌ return-await violations
async function bad() {
return Promise.resolve(42); // Error: should use 'return await'
}
// ✅ Correct usage
async function good() {
return await Promise.resolve(42); // OK: proper return await
}// Ensures Promises are properly handled
'@typescript-eslint/no-floating-promises': 'warn'
// Prevents misuse of Promises in conditions
'@typescript-eslint/no-misused-promises': ['error', { checksVoidReturn: false }]
// Enforces error handling
'@typescript-eslint/only-throw-error': 'warn'Examples:
// ❌ no-floating-promises violations
fetch('/api/data'); // Warning: Promise not handled
Promise.resolve(42); // Warning: Promise not handled
// ✅ Correct usage
await fetch('/api/data'); // OK: awaited
fetch('/api/data').catch(console.error); // OK: error handled
void fetch('/api/data'); // OK: explicitly ignored
// ❌ no-misused-promises violations
if (Promise.resolve(true)) { } // Error: Promise in condition
// ✅ Correct usage
if (await Promise.resolve(true)) { } // OK: awaited first// Prevents confusing non-null assertions
'@typescript-eslint/no-confusing-non-null-assertion': 'warn'
// Prevents unnecessary type assertions
'@typescript-eslint/no-unnecessary-type-assertion': 'warn'
// Prevents confusing void expressions
'@typescript-eslint/no-confusing-void-expression': 'warn'Examples:
// ❌ Confusing non-null assertion
if (!(obj!.prop)) { } // Warning: confusing negation with !
// ✅ Correct usage
if (!obj!.prop) { } // OK: clear intent
if (!(obj?.prop)) { } // OK: optional chaining
// ❌ Unnecessary type assertion
const num = 42 as number; // Warning: already number
const str: string = 'hello' as string; // Warning: redundant
// ✅ Correct usage
const num = 42; // OK: type inferred
const element = document.getElementById('id') as HTMLElement; // OK: needed// Prevents for-in loops on arrays
'@typescript-eslint/no-for-in-array': 'error'
// Enforces proper includes usage
'@typescript-eslint/prefer-includes': 'warn'
// Encourages string methods over indexOf
'@typescript-eslint/prefer-string-starts-ends-with': 'warn'Examples:
// ❌ no-for-in-array violation
const arr = [1, 2, 3];
for (const item in arr) { // Error: use for-of for arrays
console.log(item);
}
// ✅ Correct usage
for (const item of arr) { // OK: for-of for arrays
console.log(item);
}
// ❌ prefer-includes violation
if (arr.indexOf(item) !== -1) { } // Warning: use includes
// ✅ Correct usage
if (arr.includes(item)) { } // OK: more readable
// ❌ prefer-string-starts-ends-with violation
if (str.indexOf('prefix') === 0) { } // Warning: use startsWith
// ✅ Correct usage
if (str.startsWith('prefix')) { } // OK: clearer intent// Encourages nullish coalescing
'@typescript-eslint/prefer-nullish-coalescing': 'warn'
// Encourages optional chaining
'@typescript-eslint/prefer-optional-chain': 'warn'
// Encourages const assertions
'@typescript-eslint/prefer-as-const': 'warn'
// Encourages readonly for arrays that don't change
'@typescript-eslint/prefer-readonly': 'warn'
// Encourages ts-expect-error over ts-ignore (traditional config only)
'@typescript-eslint/prefer-ts-expect-error': 'warn'
// Additional flat config rules
'@typescript-eslint/ban-ts-comment': 'warn'Examples:
// ❌ prefer-nullish-coalescing violation
const value = input || 'default'; // Warning: may not handle 0, false correctly
// ✅ Correct usage
const value = input ?? 'default'; // OK: only null/undefined trigger default
// ❌ prefer-optional-chain violation
if (obj && obj.prop && obj.prop.method) { } // Warning: use optional chaining
// ✅ Correct usage
if (obj?.prop?.method) { } // OK: cleaner optional chaining
// ❌ prefer-as-const violation
const colors = ['red', 'blue'] as string[]; // Warning: use as const
// ✅ Correct usage
const colors = ['red', 'blue'] as const; // OK: preserves literal types
// ❌ prefer-ts-expect-error violation
// @ts-ignore
const result = riskyOperation(); // Warning: use @ts-expect-error
// ✅ Correct usage
// @ts-expect-error Known issue with library types
const result = riskyOperation(); // OK: documents expected errorType-aware linting requires TypeScript compilation and can significantly increase linting time:
// Apply only to specific directories
overrides: [
{
files: ['src/**/*.ts', '!src/**/*.test.ts'],
extends: ['universe/shared/typescript-analysis'],
parserOptions: { project: './tsconfig.json' }
}
]// Separate config for CI with full type checking
// .eslintrc.ci.js
module.exports = {
extends: ['.eslintrc.js', 'universe/shared/typescript-analysis'],
overrides: [
{
files: ['**/*.{ts,tsx}'],
parserOptions: { project: './tsconfig.json' }
}
]
};// Support for multiple TypeScript configurations
overrides: [
{
files: ['src/**/*.ts'],
parserOptions: { project: './src/tsconfig.json' }
},
{
files: ['tools/**/*.ts'],
parserOptions: { project: './tools/tsconfig.json' }
}
]Install with Tessl CLI
npx tessl i tessl/npm-eslint-config-universe