Utility functions for working with TypeScript's API, providing comprehensive tools for analyzing and manipulating TypeScript AST nodes, types, and compiler APIs.
79
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.
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.
The Compiler Options module provides:
Understanding these utilities is essential for building TypeScript tools that need to adapt their behavior based on the project's compiler configuration.
TypeScript compiler options can be categorized into different types. Boolean options specifically control on/off features and can have three states:
true: Explicitly enabledfalse: Explicitly disabledundefined: Not configured (uses default)TypeScript's strict flag is a meta-option that enables several individual strict checks. When strict: true is set, it automatically enables:
alwaysStrictnoImplicitAnynoImplicitThisstrictBindCallApplystrictFunctionTypesstrictNullChecksstrictPropertyInitializationIndividual strict options can be explicitly disabled even when strict: true is set.
type BooleanCompilerOptions = keyof {
[K in keyof ts.CompilerOptions as NonNullable<ts.CompilerOptions[K]> extends boolean ? K : never]: unknown;
}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.
Usage in type narrowing:
// Examples of boolean compiler options
const option1: BooleanCompilerOptions = "strict"; // ✓ Valid
const option2: BooleanCompilerOptions = "noImplicitAny"; // ✓ Valid
const option3: BooleanCompilerOptions = "target"; // ✗ Error - not booleantype StrictCompilerOption =
| "alwaysStrict"
| "noImplicitAny"
| "noImplicitThis"
| "strictBindCallApply"
| "strictFunctionTypes"
| "strictNullChecks"
| "strictPropertyInitialization"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.
Relationship to strict mode:
// When strict: true is set, all StrictCompilerOption values default to true
const strictOptions: StrictCompilerOption[] = [
"alwaysStrict",
"noImplicitAny",
"noImplicitThis",
"strictBindCallApply",
"strictFunctionTypes",
"strictNullChecks",
"strictPropertyInitialization"
];function isCompilerOptionEnabled(
options: ts.CompilerOptions,
option: BooleanCompilerOptions
): booleanDetermines whether a boolean compiler option is enabled, properly handling option dependencies and default values.
Parameters:
options - The compiler options object to checkoption - The name of the boolean option to testReturns: true if the option is enabled, false otherwise
Behavior:
true if the option is explicitly set to truefalse if the option is explicitly set to false or undefinedExample - Basic option checking:
import { isCompilerOptionEnabled } from "ts-api-utils";
const options: ts.CompilerOptions = {
strict: true,
noUnusedLocals: false,
exactOptionalPropertyTypes: undefined
};
// Check individual options
console.log(isCompilerOptionEnabled(options, "strict")); // true
console.log(isCompilerOptionEnabled(options, "noUnusedLocals")); // false
console.log(isCompilerOptionEnabled(options, "exactOptionalPropertyTypes")); // falseExample - Working with program options:
import { isCompilerOptionEnabled } from "ts-api-utils";
import * as ts from "typescript";
function analyzeProject(program: ts.Program) {
const options = program.getCompilerOptions();
// Adapt behavior based on compiler options
if (isCompilerOptionEnabled(options, "strict")) {
console.log("Strict mode enabled - applying strict analysis");
}
if (isCompilerOptionEnabled(options, "noImplicitAny")) {
console.log("Implicit any detection enabled");
}
if (isCompilerOptionEnabled(options, "noUnusedLocals")) {
console.log("Unused locals checking enabled");
}
}function isStrictCompilerOptionEnabled(
options: ts.CompilerOptions,
option: StrictCompilerOption
): booleanDetermines whether a strict-mode compiler option is enabled, accounting for both the global strict flag and individual option overrides.
Parameters:
options - The compiler options object to checkoption - The name of the strict option to testReturns: true if the strict option is effectively enabled, false otherwise
Resolution logic:
strict is enabledExample - Strict mode resolution:
import { isStrictCompilerOptionEnabled } from "ts-api-utils";
// Case 1: Strict mode enables all strict options
const strictOptions: ts.CompilerOptions = {
strict: true
};
console.log(isStrictCompilerOptionEnabled(strictOptions, "noImplicitAny")); // true
console.log(isStrictCompilerOptionEnabled(strictOptions, "strictNullChecks")); // true
// Case 2: Individual override disables specific strict option
const mixedOptions: ts.CompilerOptions = {
strict: true,
noImplicitAny: false // Explicitly disabled despite strict: true
};
console.log(isStrictCompilerOptionEnabled(mixedOptions, "noImplicitAny")); // false
console.log(isStrictCompilerOptionEnabled(mixedOptions, "strictNullChecks")); // true
// Case 3: Individual strict option without global strict
const individualOptions: ts.CompilerOptions = {
strict: false,
strictNullChecks: true // Explicitly enabled
};
console.log(isStrictCompilerOptionEnabled(individualOptions, "strictNullChecks")); // true
console.log(isStrictCompilerOptionEnabled(individualOptions, "noImplicitAny")); // falseExample - Conditional analysis based on strict options:
import { isStrictCompilerOptionEnabled } from "ts-api-utils";
import * as ts from "typescript";
function analyzeTypeChecking(options: ts.CompilerOptions, node: ts.Node) {
// Check for strict null checks
if (isStrictCompilerOptionEnabled(options, "strictNullChecks")) {
console.log("Strict null checks enabled - analyzing null/undefined usage");
// Perform strict null checking analysis
}
// Check for implicit any
if (isStrictCompilerOptionEnabled(options, "noImplicitAny")) {
console.log("No implicit any enabled - checking type annotations");
// Verify explicit type annotations
}
// Check for strict function types
if (isStrictCompilerOptionEnabled(options, "strictFunctionTypes")) {
console.log("Strict function types enabled - analyzing function assignments");
// Perform strict function type analysis
}
}import {
isCompilerOptionEnabled,
isStrictCompilerOptionEnabled,
BooleanCompilerOptions,
StrictCompilerOption
} from "ts-api-utils";
import * as ts from "typescript";
class CompilerConfigAnalyzer {
constructor(private options: ts.CompilerOptions) {}
analyzeStrictness(): { level: string; enabledOptions: string[] } {
const strictOptions: StrictCompilerOption[] = [
"alwaysStrict",
"noImplicitAny",
"noImplicitThis",
"strictBindCallApply",
"strictFunctionTypes",
"strictNullChecks",
"strictPropertyInitialization"
];
const enabledStrict = strictOptions.filter(option =>
isStrictCompilerOptionEnabled(this.options, option)
);
if (enabledStrict.length === strictOptions.length) {
return { level: "Full Strict Mode", enabledOptions: enabledStrict };
} else if (enabledStrict.length > 0) {
return { level: "Partial Strict Mode", enabledOptions: enabledStrict };
} else {
return { level: "Non-Strict Mode", enabledOptions: [] };
}
}
getEnabledFeatures(): string[] {
const features: BooleanCompilerOptions[] = [
"allowUnreachableCode",
"allowUnusedLabels",
"exactOptionalPropertyTypes",
"noFallthroughCasesInSwitch",
"noImplicitReturns",
"noUncheckedIndexedAccess",
"noUnusedLocals",
"noUnusedParameters"
];
return features.filter(feature =>
isCompilerOptionEnabled(this.options, feature)
);
}
}
// Usage
const config = {
strict: true,
noImplicitAny: false, // Override
noUnusedLocals: true,
exactOptionalPropertyTypes: true
};
const analyzer = new CompilerConfigAnalyzer(config);
console.log(analyzer.analyzeStrictness());
// { level: "Partial Strict Mode", enabledOptions: [...] }
console.log(analyzer.getEnabledFeatures());
// ["noUnusedLocals", "exactOptionalPropertyTypes"]import { isCompilerOptionEnabled, isStrictCompilerOptionEnabled } from "ts-api-utils";
import * as ts from "typescript";
function createLintRules(program: ts.Program) {
const options = program.getCompilerOptions();
const rules: string[] = [];
// Add rules based on compiler options
if (isStrictCompilerOptionEnabled(options, "noImplicitAny")) {
rules.push("require-explicit-types");
}
if (isStrictCompilerOptionEnabled(options, "strictNullChecks")) {
rules.push("null-checks");
rules.push("undefined-checks");
}
if (isCompilerOptionEnabled(options, "noUnusedLocals")) {
rules.push("no-unused-vars");
}
if (isCompilerOptionEnabled(options, "noFallthroughCasesInSwitch")) {
rules.push("no-fallthrough");
}
return rules;
}
// Example: Adaptive code analysis
function analyzeSourceFile(sourceFile: ts.SourceFile, options: ts.CompilerOptions) {
const hasStrictNullChecks = isStrictCompilerOptionEnabled(options, "strictNullChecks");
const hasNoImplicitAny = isStrictCompilerOptionEnabled(options, "noImplicitAny");
ts.forEachChild(sourceFile, function visit(node) {
if (ts.isVariableDeclaration(node)) {
// Only check for explicit types if noImplicitAny is enabled
if (hasNoImplicitAny && !node.type) {
console.log(`Variable ${node.name.getText()} lacks explicit type annotation`);
}
}
if (hasStrictNullChecks && ts.isPropertyAccessExpression(node)) {
// Perform null-checking analysis
console.log(`Checking null safety for ${node.getText()}`);
}
ts.forEachChild(node, visit);
});
}// ✅ Good: Use the appropriate function for the option type
if (isStrictCompilerOptionEnabled(options, "strictNullChecks")) {
// Handle strict option
}
if (isCompilerOptionEnabled(options, "allowUnreachableCode")) {
// Handle regular boolean option
}
// ❌ Avoid: Direct property access doesn't handle strict mode properly
if (options.strictNullChecks) { // May miss strict mode inheritance
// This misses cases where strict: true but strictNullChecks is undefined
}// ✅ Good: Use the typed option parameters
function checkOption(options: ts.CompilerOptions, option: BooleanCompilerOptions) {
return isCompilerOptionEnabled(options, option);
}
// ✅ Good: Use union types for multiple options
function checkAnyStrict(
options: ts.CompilerOptions,
...checkOptions: StrictCompilerOption[]
): boolean {
return checkOptions.some(option =>
isStrictCompilerOptionEnabled(options, option)
);
}// ✅ Good: Comprehensive option analysis
function describeConfiguration(options: ts.CompilerOptions): string {
const strictness = isCompilerOptionEnabled(options, "strict") ? "strict" : "non-strict";
const strictOptions = [
"noImplicitAny", "strictNullChecks", "strictFunctionTypes"
] as const;
const enabledStrict = strictOptions.filter(opt =>
isStrictCompilerOptionEnabled(options, opt)
);
return `${strictness} mode with ${enabledStrict.length} strict options enabled`;
}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.
Install with Tessl CLI
npx tessl i tessl/npm-ts-api-utilsevals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10