如何使用路径编译器选项使用tsc编译特定文件

内容来源于 Stack Overflow,遵循 CC BY-SA 4.0 许可协议进行翻译与使用。IT领域专用引擎提供翻译支持

腾讯云小微IT领域专用引擎提供翻译支持

原文
Stack Overflow用户 修改于2017-06-22
  • 该问题已被编辑
  • 提问者: Stack Overflow用户
  • 提问时间: 2017-06-21 13:02

我有几个文件我想用脚本编译。这些文件依赖于 paths 编译选项来解析其模块。由于我希望具体针对这些文件,所以我必须将它们提供给 tsc (因为我不想为这个任务创建一个针对这些文件的单独的 tsconfig.json )

我看过将 --path 参数传递给 tsc 的选项,但这是不允许的( error TS6064: Option 'paths' can only be specified in 'tsconfig.json' file. )

我可以在使用 .ts 选项时只编译特定的 paths 文件吗?

更新(22-06-17)

根据要求,有一些具体的例子:

tsconfig.json 文件中的相关设置如下:

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "Components/*": [
        "./src/Components/*"
}

因此,相关的部分是路径设置,您可以在其中创建速记,以便从某个目录导入文件。所以您可以导入像 import {header} from 'Components/header.ts' 这样的文件,而不是 import {header} from '../../Components/header.ts'

但是我需要从命令行编译特定的文件。但如果我尝试:

tsc --project tsconfig.json entryFile.ts

它会给我一个错误:

error TS5042: Option 'project' cannot be mixed with source files on a command line.

如果我试图向cli提供 paths 选项,就会得到以下错误:

error TS6064: Option 'paths' can only be specified in 'tsconfig.json' file.
浏览 24 关注 0 得票数 52
  • 得票数为Stack Overflow原文数据
原文
回答于2017-06-25
得票数 45

指定命令行上的输入文件会使您的tsconfig.json无效。

当在命令行上指定输入文件时,tsconfig.json文件将被忽略。

来自 TypeScript文档

因此,除了使用带有文件的适当“包含”(或排除)规范的tsconfig.json之外,没有其他选项。好消息是,在同一个文档中,您会发现:

tsconfig.json文件可以使用扩展属性从另一个文件继承配置。

因此,您可以做的是用如下所示的内容覆盖tsconfig的include属性:

{
  "extends": "./tsconfig.json",
  "include": [
      "src/root/index.ts"
}

所以你可以做一个脚本:

  1. 使用所需的“include”属性创建临时‘’文件
  2. 使用指定为临时tsconfig的 tsc 调用 --project

人们可能会争辩说,这是非常复杂的,并质疑他们为什么决定不适当地支持这种情况。然而,问题仍然存在,为什么我们只想编译一个项目的一个文件。在开发过程中,您可以使用watch ( -w )选项来编译更改文件,并且在构建完整的项目时,您可能希望完全编译完整的项目。

回答于2019-11-19
得票数 9

只是为了巩固@Bram的答案..。

我在我的项目中所做的是有两件事:

project/
   dist/
   docs/
   package.json
   tsconfig.json
   tsconfig-build.json

所以我有一个 tsconfig-build.json (因为我不希望 docs/ 包含在我的构建中):

// tsconfig-build.json
    "extends": "./tsconfig.json",
    "include": [
        "src/**/*"
}

那么您可以在 package.json 中使用一行

// package.json
  "scripts": {
    "build": "tsc --p tsconfig-build.json"
  },
回答于2020-03-31
得票数 12

我也需要确保项目使用 皮棉 进行编译。如果允许 tsconfig.json 和文件路径的组合,您可以直接使用 "tsc" 作为一个分阶段的命令。

作为解决办法,我创建了下面的助手脚本 scripts/tsc-lint.sh

#!/bin/bash -e
TMP=.tsconfig-lint.json
cat >$TMP <<EOF
  "extends": "./tsconfig.json",
  "include": [
for file in "$@"; do
  echo "    \"$file\"," >> $TMP
cat >>$TMP <<EOF
    "unused"
tsc --project $TMP --skipLibCheck --noEmit

然后,分阶段配置包含:

  "lint-staged": {
    "{src,tests}/**/*.ts": [
      "scripts/tsc-lint.sh"
  },

.tsconfig-lint.json 文件被添加到 .gitignore 中。

修改于2021-01-06
  • 该回答已被编辑
  • 回答者: Stack Overflow用户
  • 回答时间: 2021-01-06 12:51
得票数 0

我正是使用编译器API实现了这一点。这是一个(很大程度上)修改的 它们的最小编译器示例 版本。

import * as ts from 'typescript';
import * as fs from 'fs';
import * as path from 'path';
import * as cp from 'child_process';
import * as dm from '../src-ts/deep-merge-objects';
function compile(fileNames: string[], options: ts.CompilerOptions): void {
  const program = ts.createProgram(fileNames, options);
  const emitResult = program.emit();
  const allDiagnostics = ts
    .getPreEmitDiagnostics(program)
    .concat(emitResult.diagnostics);
  allDiagnostics.forEach((diagnostic) => {
    if (diagnostic.file) {
      const {line, character} = diagnostic.file.getLineAndCharacterOfPosition(
        diagnostic.start!
      const message = ts.flattenDiagnosticMessageText(
        diagnostic.messageText,
      console.log(
        `${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`
    } else {
      console.log(
        ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n')
  const exitCode = emitResult.emitSkipped ? 1 : 0;
  console.log(`Process exiting with code '${exitCode}'.`);
  process.exit(exitCode);
function main(): void {
  fs.mkdirSync('./dev-out',{recursive:true})
  cp.execSync('cp -r ./testlib-js ./dev-out/');
  const tscfgFilenames = [
    '@tsconfig/node14/tsconfig.json',
    path.join(process.cwd(), 'tsconfig.base.json'),
    path.join(process.cwd(), 'tsconfig.json'),
  const tscfg = tscfgFilenames.map((fn) => require(fn).compilerOptions);
  const compilerOptions: ts.CompilerOptions = dm.deepMerge(
    dm.deepMergeInnerDedupeArrays,
    ...tscfg
  if (compilerOptions.lib && compilerOptions.lib.length)
    compilerOptions.lib = compilerOptions.lib.map((s) => 'lib.' + s + '.d.ts');
  console.log(JSON.stringify(compilerOptions, null, 2));
  compile(process.argv.slice(2), compilerOptions);
try {
  main();
  if (process.exitCode === 1) console.log('compiler produced no output');
} catch (e) {
  console.error(e.message);
  process.exitCode = 2;
}

抓到的是

  • 读取配置文件。这在最初的示例中没有包含。
  • 按顺序合并配置文件。(如果使用单个文件,则没有问题)。
  • 转换 compilerOptions.lib 条目
if (compilerOptions.lib && compilerOptions.lib.length)
    compilerOptions.lib = compilerOptions.lib.map((s) => 'lib.' + s + '.d.ts');

例如,"es2020“改为"lib.es2020.d.ts”。

泛型对象合并代码如下:

// adapted from  adrian-marcelo-gallardo
// https://gist.github.com/ahtcx/0cd94e62691f539160b32ecda18af3d6#gistcomment-3257606
type objectType = Record<string, any>;
export const isObject = (obj: unknown): obj is objectType => {
  return <boolean>obj && typeof obj === 'object';
export function deepMerge(
  deepMergeInner: (target: objectType, source: objectType) => objectType,
  ...objects: objectType[]
): objectType {
  if (objects.length === 0) return {};
  if (objects.length === 1) return objects[0];
  if (objects.some((object) => !isObject(object))) {
    throw new Error('deepMerge: all values should be of type "object"');
  const target = objects.shift() as objectType;
  //console.log(JSON.stringify(target,null,2))
  let source: objectType;
  while ((source = objects.shift() as objectType)) {
    deepMergeInner(target, source);
    //console.log(JSON.stringify(target,null,2))
  return target;
export function deepMergeInnerDedupeArrays(
  target: objectType,
  source: objectType
): objectType {
  function uniquify(a: any[]): any[] {
    return a.filter((v, i) => a.indexOf(v) === i);
  Object.keys(source).forEach((key: string) => {
    const targetValue = target[key];
    const sourceValue = source[key];
    if (Array.isArray(targetValue) && Array.isArray(sourceValue)) {
      target[key] = uniquify(targetValue.concat(sourceValue));
    } else if (isObject(targetValue) && Array.isArray(sourceValue)) {
      target[key] = sourceValue;
    } else if (Array.isArray(targetValue) && isObject(sourceValue)) {
      target[key] = sourceValue;
    } else if (isObject(targetValue) && isObject(sourceValue)) {
      target[key] = deepMergeInnerDedupeArrays(
        Object.assign({}, targetValue),
        sourceValue
    } else {
      target[key] = sourceValue;
  return target;
}

另一种是目录结构。除非使用 compilerOptions.rootDir ,否则不可能获得与get相同的输出目录和所有文件。典型情况是:

  "compilerOptions": {
    "outDir": "dev-out",
    "rootDir": "./"
  },

阅读关于 rootDir在这里。 的文章

回答于2021-06-21
得票数 0

--noResolve 是这里的关键: https://www.typescriptlang.org/tsconfig/#noResolve

例如:

// tsconfig.myFile.json
  // "extends": "./tsconfig.json",
  "include": [
    "myFile.ts"
    "compilerOptions": {
        "noResolve": true
}

$ tsc --project tsconfig.myFile.json

还有一些方法可以包含 --noResolve 和一些输出标志,这样就可以只使用命令行。

回答于2022-07-20
得票数 1

基于@sampo的回答。

我们可以在每个包目录中创建一个临时 .tsconfig-lint.json ,其中包括属于每个目录下的阶段性TS文件的列表。

它将为每个包运行一个 tsc ,并报告任何不是0的状态代码。

// <root>/tsc-lint.js
// Usage: `yarn lint-staged` (doesn't support --relative)
// In package.json."lint-staged"."*.{ts,tsx}": `node ./tsc-lint.js`
// Run from workspace root
const chalk = require('chalk');
const spawn = require('cross-spawn');
const fs = require('fs');
const path = require('path');
// Relative path of package locations (relative to root)
const packages = [
  'packages/a',
  'packages/b',
  'packages/c',
const TSCONFIG_LINT_FILE_NAME = '.tsconfig-lint.json';
const files = process.argv.slice(2);
Promise.all(
  packages.map((package) => {
    const absolutePackagePath = path.resolve(package);
    const includedFiles = files.filter((file) => file.startsWith(absolutePackagePath));
    if (includedFiles.length) {
      const tsconfig = {
        extends: './tsconfig.json',
        include: [...includedFiles, '**/*.d.ts'],
      const tsconfigLintPath = `${package}/${TSCONFIG_LINT_FILE_NAME}`;
      fs.writeFileSync(tsconfigLintPath, JSON.stringify(tsconfig, null, 2));
      return spawn.sync(path.resolve('./node_modules/.bin/tsc'), [
        '--project',
        tsconfigLintPath,
        '--noEmit',
        '--skipLibCheck',
    return undefined;
  .then((children) => Promise.all(children.filter((child) => child && child.status !== 0)))
  .then((children) => Promise.all(children.map((child) => child.stdout)))
  .then((errors) => {
    if (errors.length) {
      throw errors;
    return errors;