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.