Edit
Explained in a comment below by @Hiroki Osame, the use of ts.parseJsonConfigFileContent
in this answer allowed for automatic handling of the extends
without manual intervention.
Another insightful contribution can be found in @Simon Buchan's response on this page.
Short Answer
This function reads compiler options from a tsconfig file and manages tsconfig extends
keyword inheritance seamlessly.
function getCompilerOptionsJSONFollowExtends(filename: string): {[key: string]: any} {
let compopts = {};
const config = ts.readConfigFile(filename, ts.sys.readFile).config;
if (config.extends) {
const rqrpath = require.resolve(config.extends);
compopts = getCompilerOptionsJSONFollowExtends(rqrpath);
}
return {
...compopts,
...config.compilerOptions,
};
}
The resulting JSON can be converted to type ts.CompilerOptions
using:
const jsonCompopts = getCompilerOptionsJSONFollowExtends('tsconfig.json')
const tmp = ts.convertCompilerOptionsFromJson(jsonCompopts,'')
if (tmp.errors.length>0) throw new Error('...')
const tsCompopts: ts.CompilerOptions = tmp.options
TL;DR
Key functions include:
ts.readConfigFile
ts.parseConfigFileTextToJson
ts.convertCompilerOptionsFromJson
ts.parseJsonConfigFileContent
ts.parseJsonSourceFileConfigFileContent
Only the first three functions are discussed here:
ts.readConfigFile
console.log(
JSON.stringify(
ts.readConfigFile('./tsconfig.base.json', ts.sys.readFile),
null,
2
)
);
The content of tsconfig.base.json
:
{
"extends": "@tsconfig/node14/tsconfig.json",
"compilerOptions": {
"declaration": true,
"skipLibCheck": true,
"sourceMap": true,
"lib": ["es2020"]
}
}
ts.parseConfigFileTextToJson
const parsed2 = ts.parseConfigFileTextToJson(
'',
`
{
"extends": "@tsconfig/node14/tsconfig.json",
"compilerOptions": {
"declaration": true,
"skipLibCheck": true,
"sourceMap": true,
"lib": ["es2020"]
}
}
`);
console.log(JSON.stringify(parsed2, null, 2));
ts.convertCompilerOptionsFromJson
const parsed1 = ts.convertCompilerOptionsFromJson(
{
lib: ['es2020'],
module: 'commonjs',
target: 'es2020',
},
''
);
console.log(JSON.stringify(parsed1, null, 2));
Discussion / Extends
When dealing with the extends
keyword:
are useful. However, automatic extension following requires more complex logic.
How to Follow Extends Using API
A sample implementation:
function getCompileOptionsJSONFollowExtends(filename: string): {[key: string]: any} {
let compopts: ts.CompilerOptions = {};
const config = ts.readConfigFile(filename, ts.sys.readFile).config;
if (config.extends) {
const rqrpath = require.resolve(config.extends);
compopts = getCompileOptionsJSONFollowExtends(rqrpath);
}
compopts = {
...compopts,
...config.compilerOptions,
};
return compopts;
}
Test run:
const jsonCompopts = getCompileOptionsJSONFollowExtends('./tsconfig.base.json')
console.log(JSON.stringify(jsonCompopts,null,2))
const tsCompopts = ts.convertCompilerOptionsFromJson(jsonCompopts,'')
console.log(JSON.stringify(tsCompopts,null,2))
console.log('');