or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

compiler-options.mdindex.mdnode-analysis.mdsyntax-utilities.mdtype-system.mdusage-analysis.md

compiler-options.mddocs/

0

# Compiler Options

1

2

Compiler Options utilities provide a robust interface for analyzing and working with TypeScript compiler options. These utilities simplify checking whether specific compiler options are enabled, handling the complex interdependencies between options, and accounting for TypeScript's strict mode hierarchy.

3

4

## Overview

5

6

TypeScript's compiler behavior is controlled by numerous compiler options that can be configured in `tsconfig.json` or passed via command line arguments. These options often have complex relationships - some options enable others, strict mode affects multiple individual options, and boolean options can have undefined, true, or false values.

7

8

The Compiler Options module provides:

9

10

1. **Option Testing**: Safe checking of boolean compiler options

11

2. **Strict Mode Handling**: Proper resolution of strict-mode-related options

12

3. **Type Safety**: Strongly typed interfaces for compiler options

13

14

Understanding these utilities is essential for building TypeScript tools that need to adapt their behavior based on the project's compiler configuration.

15

16

## Core Concepts

17

18

### Boolean Compiler Options

19

20

TypeScript compiler options can be categorized into different types. Boolean options specifically control on/off features and can have three states:

21

- `true`: Explicitly enabled

22

- `false`: Explicitly disabled

23

- `undefined`: Not configured (uses default)

24

25

### Strict Mode Hierarchy

26

27

TypeScript's `strict` flag is a meta-option that enables several individual strict checks. When `strict: true` is set, it automatically enables:

28

- `alwaysStrict`

29

- `noImplicitAny`

30

- `noImplicitThis`

31

- `strictBindCallApply`

32

- `strictFunctionTypes`

33

- `strictNullChecks`

34

- `strictPropertyInitialization`

35

36

Individual strict options can be explicitly disabled even when `strict: true` is set.

37

38

## Types

39

40

### BooleanCompilerOptions

41

42

```typescript { .api }

43

type BooleanCompilerOptions = keyof {

44

[K in keyof ts.CompilerOptions as NonNullable<ts.CompilerOptions[K]> extends boolean ? K : never]: unknown;

45

}

46

```

47

48

A type representing all compiler options that accept boolean values. This mapped type extracts only those options from `ts.CompilerOptions` where the value type extends `boolean`.

49

50

**Usage in type narrowing:**

51

```typescript

52

// Examples of boolean compiler options

53

const option1: BooleanCompilerOptions = "strict"; // ✓ Valid

54

const option2: BooleanCompilerOptions = "noImplicitAny"; // ✓ Valid

55

const option3: BooleanCompilerOptions = "target"; // ✗ Error - not boolean

56

```

57

58

### StrictCompilerOption

59

60

```typescript { .api }

61

type StrictCompilerOption =

62

| "alwaysStrict"

63

| "noImplicitAny"

64

| "noImplicitThis"

65

| "strictBindCallApply"

66

| "strictFunctionTypes"

67

| "strictNullChecks"

68

| "strictPropertyInitialization"

69

```

70

71

A union type representing all compiler options that are controlled by the `strict` flag. These options are automatically enabled when `strict: true` is set, but can be individually overridden.

72

73

**Relationship to strict mode:**

74

```typescript

75

// When strict: true is set, all StrictCompilerOption values default to true

76

const strictOptions: StrictCompilerOption[] = [

77

"alwaysStrict",

78

"noImplicitAny",

79

"noImplicitThis",

80

"strictBindCallApply",

81

"strictFunctionTypes",

82

"strictNullChecks",

83

"strictPropertyInitialization"

84

];

85

```

86

87

## Functions

88

89

### isCompilerOptionEnabled

90

91

```typescript { .api }

92

function isCompilerOptionEnabled(

93

options: ts.CompilerOptions,

94

option: BooleanCompilerOptions

95

): boolean

96

```

97

98

Determines whether a boolean compiler option is enabled, properly handling option dependencies and default values.

99

100

**Parameters:**

101

- `options` - The compiler options object to check

102

- `option` - The name of the boolean option to test

103

104

**Returns:** `true` if the option is enabled, `false` otherwise

105

106

**Behavior:**

107

- Returns `true` if the option is explicitly set to `true`

108

- Returns `false` if the option is explicitly set to `false` or `undefined`

109

- Handles complex interdependencies between options

110

111

**Example - Basic option checking:**

112

```typescript

113

import { isCompilerOptionEnabled } from "ts-api-utils";

114

115

const options: ts.CompilerOptions = {

116

strict: true,

117

noUnusedLocals: false,

118

exactOptionalPropertyTypes: undefined

119

};

120

121

// Check individual options

122

console.log(isCompilerOptionEnabled(options, "strict")); // true

123

console.log(isCompilerOptionEnabled(options, "noUnusedLocals")); // false

124

console.log(isCompilerOptionEnabled(options, "exactOptionalPropertyTypes")); // false

125

```

126

127

**Example - Working with program options:**

128

```typescript

129

import { isCompilerOptionEnabled } from "ts-api-utils";

130

import * as ts from "typescript";

131

132

function analyzeProject(program: ts.Program) {

133

const options = program.getCompilerOptions();

134

135

// Adapt behavior based on compiler options

136

if (isCompilerOptionEnabled(options, "strict")) {

137

console.log("Strict mode enabled - applying strict analysis");

138

}

139

140

if (isCompilerOptionEnabled(options, "noImplicitAny")) {

141

console.log("Implicit any detection enabled");

142

}

143

144

if (isCompilerOptionEnabled(options, "noUnusedLocals")) {

145

console.log("Unused locals checking enabled");

146

}

147

}

148

```

149

150

### isStrictCompilerOptionEnabled

151

152

```typescript { .api }

153

function isStrictCompilerOptionEnabled(

154

options: ts.CompilerOptions,

155

option: StrictCompilerOption

156

): boolean

157

```

158

159

Determines whether a strict-mode compiler option is enabled, accounting for both the global `strict` flag and individual option overrides.

160

161

**Parameters:**

162

- `options` - The compiler options object to check

163

- `option` - The name of the strict option to test

164

165

**Returns:** `true` if the strict option is effectively enabled, `false` otherwise

166

167

**Resolution logic:**

168

1. If the specific option is explicitly set (true/false), use that value

169

2. If the specific option is undefined, check if `strict` is enabled

170

3. Return the effective boolean value

171

172

**Example - Strict mode resolution:**

173

```typescript

174

import { isStrictCompilerOptionEnabled } from "ts-api-utils";

175

176

// Case 1: Strict mode enables all strict options

177

const strictOptions: ts.CompilerOptions = {

178

strict: true

179

};

180

181

console.log(isStrictCompilerOptionEnabled(strictOptions, "noImplicitAny")); // true

182

console.log(isStrictCompilerOptionEnabled(strictOptions, "strictNullChecks")); // true

183

184

// Case 2: Individual override disables specific strict option

185

const mixedOptions: ts.CompilerOptions = {

186

strict: true,

187

noImplicitAny: false // Explicitly disabled despite strict: true

188

};

189

190

console.log(isStrictCompilerOptionEnabled(mixedOptions, "noImplicitAny")); // false

191

console.log(isStrictCompilerOptionEnabled(mixedOptions, "strictNullChecks")); // true

192

193

// Case 3: Individual strict option without global strict

194

const individualOptions: ts.CompilerOptions = {

195

strict: false,

196

strictNullChecks: true // Explicitly enabled

197

};

198

199

console.log(isStrictCompilerOptionEnabled(individualOptions, "strictNullChecks")); // true

200

console.log(isStrictCompilerOptionEnabled(individualOptions, "noImplicitAny")); // false

201

```

202

203

**Example - Conditional analysis based on strict options:**

204

```typescript

205

import { isStrictCompilerOptionEnabled } from "ts-api-utils";

206

import * as ts from "typescript";

207

208

function analyzeTypeChecking(options: ts.CompilerOptions, node: ts.Node) {

209

// Check for strict null checks

210

if (isStrictCompilerOptionEnabled(options, "strictNullChecks")) {

211

console.log("Strict null checks enabled - analyzing null/undefined usage");

212

// Perform strict null checking analysis

213

}

214

215

// Check for implicit any

216

if (isStrictCompilerOptionEnabled(options, "noImplicitAny")) {

217

console.log("No implicit any enabled - checking type annotations");

218

// Verify explicit type annotations

219

}

220

221

// Check for strict function types

222

if (isStrictCompilerOptionEnabled(options, "strictFunctionTypes")) {

223

console.log("Strict function types enabled - analyzing function assignments");

224

// Perform strict function type analysis

225

}

226

}

227

```

228

229

## Practical Examples

230

231

### Building a Configuration Analyzer

232

233

```typescript

234

import {

235

isCompilerOptionEnabled,

236

isStrictCompilerOptionEnabled,

237

BooleanCompilerOptions,

238

StrictCompilerOption

239

} from "ts-api-utils";

240

import * as ts from "typescript";

241

242

class CompilerConfigAnalyzer {

243

constructor(private options: ts.CompilerOptions) {}

244

245

analyzeStrictness(): { level: string; enabledOptions: string[] } {

246

const strictOptions: StrictCompilerOption[] = [

247

"alwaysStrict",

248

"noImplicitAny",

249

"noImplicitThis",

250

"strictBindCallApply",

251

"strictFunctionTypes",

252

"strictNullChecks",

253

"strictPropertyInitialization"

254

];

255

256

const enabledStrict = strictOptions.filter(option =>

257

isStrictCompilerOptionEnabled(this.options, option)

258

);

259

260

if (enabledStrict.length === strictOptions.length) {

261

return { level: "Full Strict Mode", enabledOptions: enabledStrict };

262

} else if (enabledStrict.length > 0) {

263

return { level: "Partial Strict Mode", enabledOptions: enabledStrict };

264

} else {

265

return { level: "Non-Strict Mode", enabledOptions: [] };

266

}

267

}

268

269

getEnabledFeatures(): string[] {

270

const features: BooleanCompilerOptions[] = [

271

"allowUnreachableCode",

272

"allowUnusedLabels",

273

"exactOptionalPropertyTypes",

274

"noFallthroughCasesInSwitch",

275

"noImplicitReturns",

276

"noUncheckedIndexedAccess",

277

"noUnusedLocals",

278

"noUnusedParameters"

279

];

280

281

return features.filter(feature =>

282

isCompilerOptionEnabled(this.options, feature)

283

);

284

}

285

}

286

287

// Usage

288

const config = {

289

strict: true,

290

noImplicitAny: false, // Override

291

noUnusedLocals: true,

292

exactOptionalPropertyTypes: true

293

};

294

295

const analyzer = new CompilerConfigAnalyzer(config);

296

console.log(analyzer.analyzeStrictness());

297

// { level: "Partial Strict Mode", enabledOptions: [...] }

298

299

console.log(analyzer.getEnabledFeatures());

300

// ["noUnusedLocals", "exactOptionalPropertyTypes"]

301

```

302

303

### Conditional Tool Behavior

304

305

```typescript

306

import { isCompilerOptionEnabled, isStrictCompilerOptionEnabled } from "ts-api-utils";

307

import * as ts from "typescript";

308

309

function createLintRules(program: ts.Program) {

310

const options = program.getCompilerOptions();

311

const rules: string[] = [];

312

313

// Add rules based on compiler options

314

if (isStrictCompilerOptionEnabled(options, "noImplicitAny")) {

315

rules.push("require-explicit-types");

316

}

317

318

if (isStrictCompilerOptionEnabled(options, "strictNullChecks")) {

319

rules.push("null-checks");

320

rules.push("undefined-checks");

321

}

322

323

if (isCompilerOptionEnabled(options, "noUnusedLocals")) {

324

rules.push("no-unused-vars");

325

}

326

327

if (isCompilerOptionEnabled(options, "noFallthroughCasesInSwitch")) {

328

rules.push("no-fallthrough");

329

}

330

331

return rules;

332

}

333

334

// Example: Adaptive code analysis

335

function analyzeSourceFile(sourceFile: ts.SourceFile, options: ts.CompilerOptions) {

336

const hasStrictNullChecks = isStrictCompilerOptionEnabled(options, "strictNullChecks");

337

const hasNoImplicitAny = isStrictCompilerOptionEnabled(options, "noImplicitAny");

338

339

ts.forEachChild(sourceFile, function visit(node) {

340

if (ts.isVariableDeclaration(node)) {

341

// Only check for explicit types if noImplicitAny is enabled

342

if (hasNoImplicitAny && !node.type) {

343

console.log(`Variable ${node.name.getText()} lacks explicit type annotation`);

344

}

345

}

346

347

if (hasStrictNullChecks && ts.isPropertyAccessExpression(node)) {

348

// Perform null-checking analysis

349

console.log(`Checking null safety for ${node.getText()}`);

350

}

351

352

ts.forEachChild(node, visit);

353

});

354

}

355

```

356

357

## Best Practices

358

359

### Option Checking Patterns

360

361

```typescript

362

// ✅ Good: Use the appropriate function for the option type

363

if (isStrictCompilerOptionEnabled(options, "strictNullChecks")) {

364

// Handle strict option

365

}

366

367

if (isCompilerOptionEnabled(options, "allowUnreachableCode")) {

368

// Handle regular boolean option

369

}

370

371

// ❌ Avoid: Direct property access doesn't handle strict mode properly

372

if (options.strictNullChecks) { // May miss strict mode inheritance

373

// This misses cases where strict: true but strictNullChecks is undefined

374

}

375

```

376

377

### Type Safety

378

379

```typescript

380

// ✅ Good: Use the typed option parameters

381

function checkOption(options: ts.CompilerOptions, option: BooleanCompilerOptions) {

382

return isCompilerOptionEnabled(options, option);

383

}

384

385

// ✅ Good: Use union types for multiple options

386

function checkAnyStrict(

387

options: ts.CompilerOptions,

388

...checkOptions: StrictCompilerOption[]

389

): boolean {

390

return checkOptions.some(option =>

391

isStrictCompilerOptionEnabled(options, option)

392

);

393

}

394

```

395

396

### Configuration Analysis

397

398

```typescript

399

// ✅ Good: Comprehensive option analysis

400

function describeConfiguration(options: ts.CompilerOptions): string {

401

const strictness = isCompilerOptionEnabled(options, "strict") ? "strict" : "non-strict";

402

const strictOptions = [

403

"noImplicitAny", "strictNullChecks", "strictFunctionTypes"

404

] as const;

405

406

const enabledStrict = strictOptions.filter(opt =>

407

isStrictCompilerOptionEnabled(options, opt)

408

);

409

410

return `${strictness} mode with ${enabledStrict.length} strict options enabled`;

411

}

412

```

413

414

The Compiler Options utilities provide a reliable foundation for building TypeScript tools that need to adapt their behavior based on the project's configuration, ensuring proper handling of the complex relationships between different compiler options.