Utilities for working with TypeScript + ESLint together
—
The JSONSchema namespace provides comprehensive JSON Schema Draft 04 types for defining ESLint rule configurations with full type safety.
import { JSONSchema } from '@typescript-eslint/utils';// Valid JSON Schema type names
type JSONSchema4TypeName =
| 'any'
| 'array'
| 'boolean'
| 'integer'
| 'null'
| 'number'
| 'object'
| 'string';
// Basic JSON values
type JSONSchema4Type = boolean | number | string | null;
// Extended JSON types including arrays and objects
type JSONSchema4TypeExtended =
| JSONSchema4Type
| JSONSchema4Object
| JSONSchema4Array;
// JSON Schema version identifier
type JSONSchema4Version = string;// Object with string keys and extended JSON values
interface JSONSchema4Object {
[key: string]: JSONSchema4TypeExtended;
}
// Array of extended JSON values
interface JSONSchema4Array extends Array<JSONSchema4TypeExtended> {}interface JSONSchema4Base {
// Schema metadata
$schema?: JSONSchema4Version;
$ref?: string;
title?: string;
description?: string;
// Default value
default?: JSONSchema4TypeExtended;
// Schema composition
allOf?: JSONSchema4[];
anyOf?: JSONSchema4[];
oneOf?: JSONSchema4[];
not?: JSONSchema4;
// Type specification
type?: JSONSchema4TypeName | JSONSchema4TypeName[];
// Definitions and references
definitions?: { [key: string]: JSONSchema4 };
$defs?: { [key: string]: JSONSchema4 };
// Enumeration
enum?: JSONSchema4TypeExtended[];
// Conditional schemas
if?: JSONSchema4;
then?: JSONSchema4;
else?: JSONSchema4;
}interface JSONSchema4RefSchema extends JSONSchema4Base {
$ref: string;
}
// Usage example
const refSchema: JSONSchema.JSONSchema4RefSchema = {
$ref: '#/definitions/MyType'
};// AllOf schema - AND logic
interface JSONSchema4AllOfSchema extends JSONSchema4Base {
allOf: JSONSchema4[];
}
// AnyOf schema - OR logic
interface JSONSchema4AnyOfSchema extends JSONSchema4Base {
anyOf: JSONSchema4[];
}
// OneOf schema - XOR logic
interface JSONSchema4OneOfSchema extends JSONSchema4Base {
oneOf: JSONSchema4[];
}
// Usage examples
const allOfSchema: JSONSchema.JSONSchema4AllOfSchema = {
allOf: [
{ type: 'object' },
{
properties: {
name: { type: 'string' }
}
}
]
};
const anyOfSchema: JSONSchema.JSONSchema4AnyOfSchema = {
anyOf: [
{ type: 'string' },
{ type: 'number' }
]
};interface JSONSchema4MultiSchema extends JSONSchema4Base {
type: JSONSchema4TypeName[];
}
// Usage example
const multiTypeSchema: JSONSchema.JSONSchema4MultiSchema = {
type: ['string', 'number'],
description: 'String or number value'
};interface JSONSchema4ObjectSchema extends JSONSchema4Base {
type: 'object';
// Property definitions
properties?: { [key: string]: JSONSchema4 };
additionalProperties?: boolean | JSONSchema4;
// Property requirements
required?: string[];
// Property count constraints
minProperties?: number;
maxProperties?: number;
// Property name patterns
patternProperties?: { [pattern: string]: JSONSchema4 };
// Property dependencies
dependencies?: {
[key: string]: JSONSchema4 | string[];
};
// Property names validation
propertyNames?: JSONSchema4;
}// Simple object schema
const userSchema: JSONSchema.JSONSchema4ObjectSchema = {
type: 'object',
properties: {
name: { type: 'string' },
age: { type: 'integer', minimum: 0 },
email: {
type: 'string',
format: 'email'
}
},
required: ['name', 'email'],
additionalProperties: false
};
// Object with pattern properties
const configSchema: JSONSchema.JSONSchema4ObjectSchema = {
type: 'object',
properties: {
version: { type: 'string' }
},
patternProperties: {
'^rule-.+': {
type: 'object',
properties: {
enabled: { type: 'boolean' },
level: { enum: ['error', 'warn', 'off'] }
}
}
},
additionalProperties: false
};
// Object with dependencies
const conditionalSchema: JSONSchema.JSONSchema4ObjectSchema = {
type: 'object',
properties: {
useCache: { type: 'boolean' },
cacheDir: { type: 'string' },
cacheTTL: { type: 'integer' }
},
dependencies: {
cacheDir: ['useCache'],
cacheTTL: ['useCache']
}
};interface JSONSchema4ArraySchema extends JSONSchema4Base {
type: 'array';
// Item validation
items?: JSONSchema4 | JSONSchema4[];
additionalItems?: boolean | JSONSchema4;
// Length constraints
minItems?: number;
maxItems?: number;
// Uniqueness
uniqueItems?: boolean;
// Contains validation (Draft 6+, but commonly supported)
contains?: JSONSchema4;
}// Simple array schema
const stringArraySchema: JSONSchema.JSONSchema4ArraySchema = {
type: 'array',
items: { type: 'string' },
minItems: 1,
uniqueItems: true
};
// Tuple schema with specific items
const tupleSchema: JSONSchema.JSONSchema4ArraySchema = {
type: 'array',
items: [
{ type: 'string' },
{ type: 'number' },
{ type: 'boolean' }
],
additionalItems: false,
minItems: 2,
maxItems: 3
};
// Array with complex item validation
const complexArraySchema: JSONSchema.JSONSchema4ArraySchema = {
type: 'array',
items: {
type: 'object',
properties: {
id: { type: 'integer' },
name: { type: 'string' },
tags: {
type: 'array',
items: { type: 'string' }
}
},
required: ['id', 'name']
},
minItems: 0,
maxItems: 100
};interface JSONSchema4StringSchema extends JSONSchema4Base {
type: 'string';
// Length constraints
minLength?: number;
maxLength?: number;
// Pattern matching
pattern?: string;
// Format validation
format?:
| 'date-time'
| 'date'
| 'time'
| 'email'
| 'hostname'
| 'ipv4'
| 'ipv6'
| 'uri'
| 'uri-reference'
| 'regex'
| string;
}// Basic string validation
const nameSchema: JSONSchema.JSONSchema4StringSchema = {
type: 'string',
minLength: 1,
maxLength: 100,
pattern: '^[A-Za-z\\s]+$'
};
// Email format validation
const emailSchema: JSONSchema.JSONSchema4StringSchema = {
type: 'string',
format: 'email'
};
// Enum string values
const modeSchema: JSONSchema.JSONSchema4StringSchema = {
type: 'string',
enum: ['strict', 'loose', 'off']
};
// Pattern-based validation
const identifierSchema: JSONSchema.JSONSchema4StringSchema = {
type: 'string',
pattern: '^[a-zA-Z_][a-zA-Z0-9_]*$',
description: 'Valid JavaScript identifier'
};interface JSONSchema4NumberSchema extends JSONSchema4Base {
type: 'number' | 'integer';
// Range constraints
minimum?: number;
maximum?: number;
exclusiveMinimum?: boolean | number;
exclusiveMaximum?: boolean | number;
// Multiple validation
multipleOf?: number;
}// Integer with range
const portSchema: JSONSchema.JSONSchema4NumberSchema = {
type: 'integer',
minimum: 1,
maximum: 65535
};
// Float with precision
const percentageSchema: JSONSchema.JSONSchema4NumberSchema = {
type: 'number',
minimum: 0,
maximum: 100,
multipleOf: 0.01
};
// Exclusive bounds
const positiveNumberSchema: JSONSchema.JSONSchema4NumberSchema = {
type: 'number',
exclusiveMinimum: true,
minimum: 0
};interface JSONSchema4BooleanSchema extends JSONSchema4Base {
type: 'boolean';
}
const booleanSchema: JSONSchema.JSONSchema4BooleanSchema = {
type: 'boolean',
default: false
};interface JSONSchema4NullSchema extends JSONSchema4Base {
type: 'null';
}
const nullSchema: JSONSchema.JSONSchema4NullSchema = {
type: 'null'
};interface JSONSchema4AnySchema extends JSONSchema4Base {
type?: 'any';
}
const anyValueSchema: JSONSchema.JSONSchema4AnySchema = {
description: 'Any value is allowed'
};// Main JSON Schema type - union of all schema types
type JSONSchema4 =
| JSONSchema4RefSchema
| JSONSchema4AllOfSchema
| JSONSchema4AnyOfSchema
| JSONSchema4OneOfSchema
| JSONSchema4MultiSchema
| JSONSchema4ObjectSchema
| JSONSchema4ArraySchema
| JSONSchema4StringSchema
| JSONSchema4NumberSchema
| JSONSchema4BooleanSchema
| JSONSchema4NullSchema
| JSONSchema4AnySchema
| boolean; // Boolean schemas (true = allow any, false = allow none)// Basic boolean option
const simpleBooleanSchema: JSONSchema.JSONSchema4 = {
type: 'boolean'
};
// Simple object configuration
const basicConfigSchema: JSONSchema.JSONSchema4 = {
type: 'object',
properties: {
enabled: { type: 'boolean' },
level: {
type: 'string',
enum: ['error', 'warn', 'off']
}
},
additionalProperties: false
};// Array of options with different types
const complexRuleSchema: JSONSchema.JSONSchema4[] = [
{
// First option: mode selection
type: 'string',
enum: ['strict', 'loose', 'off']
},
{
// Second option: detailed configuration
type: 'object',
properties: {
exceptions: {
type: 'array',
items: { type: 'string' },
uniqueItems: true
},
ignorePatterns: {
type: 'array',
items: {
type: 'string',
format: 'regex'
}
},
overrides: {
type: 'object',
patternProperties: {
'.*': {
type: 'object',
properties: {
mode: { enum: ['strict', 'loose', 'inherit'] },
exceptions: {
type: 'array',
items: { type: 'string' }
}
},
additionalProperties: false
}
}
}
},
additionalProperties: false
}
];// Schema with conditional validation
const conditionalRuleSchema: JSONSchema.JSONSchema4 = {
type: 'object',
properties: {
mode: {
type: 'string',
enum: ['manual', 'auto']
},
manualConfig: {
type: 'object',
properties: {
patterns: {
type: 'array',
items: { type: 'string' }
}
}
},
autoConfig: {
type: 'object',
properties: {
threshold: { type: 'number' },
recursive: { type: 'boolean' }
}
}
},
allOf: [
{
if: {
properties: { mode: { const: 'manual' } }
},
then: {
required: ['manualConfig'],
not: {
required: ['autoConfig']
}
}
},
{
if: {
properties: { mode: { const: 'auto' } }
},
then: {
required: ['autoConfig'],
not: {
required: ['manualConfig']
}
}
}
],
required: ['mode']
};import { ESLintUtils, JSONSchema } from '@typescript-eslint/utils';
// Define schema with full typing
const ruleOptionsSchema: JSONSchema.JSONSchema4[] = [
{
type: 'object',
properties: {
checkReturns: { type: 'boolean' },
checkParams: { type: 'boolean' },
ignorePrivate: { type: 'boolean' },
patterns: {
type: 'array',
items: { type: 'string' },
minItems: 0
}
},
additionalProperties: false
}
];
type Options = [{
checkReturns?: boolean;
checkParams?: boolean;
ignorePrivate?: boolean;
patterns?: string[];
}];
const createRule = ESLintUtils.RuleCreator(name => `https://example.com/${name}`);
export default createRule<Options, 'missingType'>({
name: 'typed-rule-example',
meta: {
type: 'problem',
docs: {
description: 'Example of type-safe rule with JSON Schema'
},
messages: {
missingType: 'Missing type annotation'
},
schema: ruleOptionsSchema // Fully typed schema
},
defaultOptions: [{
checkReturns: true,
checkParams: true,
ignorePrivate: false,
patterns: []
}],
create(context, [options]) {
// options is fully typed based on schema
const { checkReturns, checkParams, ignorePrivate, patterns } = options;
return {
FunctionDeclaration(node) {
if (ignorePrivate && node.id?.name.startsWith('_')) {
return;
}
// Rule implementation using typed options
}
};
}
});// Helper to create strict object schemas
function createStrictObjectSchema(properties: Record<string, JSONSchema.JSONSchema4>): JSONSchema.JSONSchema4ObjectSchema {
return {
type: 'object',
properties,
additionalProperties: false
};
}
// Helper to create enum schemas
function createEnumSchema<T extends readonly string[]>(values: T): JSONSchema.JSONSchema4StringSchema {
return {
type: 'string',
enum: [...values]
};
}
// Usage examples
const strictConfigSchema = createStrictObjectSchema({
mode: createEnumSchema(['strict', 'loose'] as const),
level: createEnumSchema(['error', 'warn'] as const),
enabled: { type: 'boolean' }
});
// Array schema helper
function createArraySchema(itemSchema: JSONSchema.JSONSchema4, options?: {
minItems?: number;
maxItems?: number;
uniqueItems?: boolean;
}): JSONSchema.JSONSchema4ArraySchema {
return {
type: 'array',
items: itemSchema,
...options
};
}
const stringArraySchema = createArraySchema(
{ type: 'string', minLength: 1 },
{ minItems: 0, uniqueItems: true }
);import { ESLintUtils, JSONSchema } from '@typescript-eslint/utils';
// Comprehensive rule schema
const comprehensiveRuleSchema: JSONSchema.JSONSchema4[] = [
{
type: 'object',
properties: {
// Basic options
enabled: { type: 'boolean' },
severity: {
type: 'string',
enum: ['error', 'warning', 'suggestion']
},
// Array configurations
ignorePatterns: {
type: 'array',
items: {
type: 'string',
minLength: 1
},
uniqueItems: true
},
// Nested object configuration
typeChecking: {
type: 'object',
properties: {
enabled: { type: 'boolean' },
strictMode: { type: 'boolean' },
allowedTypes: {
type: 'array',
items: {
type: 'string',
enum: ['string', 'number', 'boolean', 'object', 'array']
}
}
},
additionalProperties: false,
required: ['enabled']
},
// Conditional configuration
advanced: {
type: 'object',
properties: {
mode: { enum: ['auto', 'manual'] },
autoSettings: {
type: 'object',
properties: {
threshold: { type: 'number', minimum: 0, maximum: 1 }
}
},
manualSettings: {
type: 'object',
properties: {
rules: {
type: 'array',
items: { type: 'string' }
}
}
}
},
allOf: [
{
if: { properties: { mode: { const: 'auto' } } },
then: { required: ['autoSettings'] }
},
{
if: { properties: { mode: { const: 'manual' } } },
then: { required: ['manualSettings'] }
}
]
}
},
additionalProperties: false
}
];
type ComplexOptions = [{
enabled?: boolean;
severity?: 'error' | 'warning' | 'suggestion';
ignorePatterns?: string[];
typeChecking?: {
enabled: boolean;
strictMode?: boolean;
allowedTypes?: Array<'string' | 'number' | 'boolean' | 'object' | 'array'>;
};
advanced?: {
mode: 'auto' | 'manual';
autoSettings?: { threshold: number };
manualSettings?: { rules: string[] };
};
}];
const createRule = ESLintUtils.RuleCreator(name => `https://example.com/${name}`);
export default createRule<ComplexOptions, 'violation'>({
name: 'comprehensive-schema-example',
meta: {
type: 'problem',
docs: { description: 'Demonstrates comprehensive JSON Schema usage' },
messages: { violation: 'Rule violation detected' },
schema: comprehensiveRuleSchema
},
defaultOptions: [{
enabled: true,
severity: 'error',
ignorePatterns: [],
typeChecking: { enabled: true }
}],
create(context, [options]) {
// Fully typed options with schema validation
return {
Program() {
// Implementation using validated options
}
};
}
});Install with Tessl CLI
npx tessl i tessl/npm-typescript-eslint--utils