# Configuring TypeScript Path Resolution with tsconfig.json Aliases

> Master TypeScript path resolution using tsconfig.json aliases. Learn how code-review-graph maps imports to absolute paths with pattern matching and filesystem probing.

- Repository: [Tirth Kanani/code-review-graph](https://github.com/tirth8205/code-review-graph)
- Tags: how-to-guide
- Published: 2026-07-18

---

**The code-review-graph repository resolves TypeScript path aliases by walking up the directory tree to locate [`tsconfig.json`](https://github.com/tirth8205/code-review-graph/blob/main/tsconfig.json), parsing the `paths` configuration, and mapping aliased imports to absolute file paths using pattern matching and filesystem probing.**

The `code-review-graph` tool parses JavaScript and TypeScript projects to build dependency graphs, but path aliases like `@/utils` require special handling to resolve correctly. When the parser encounters a non-relative import, it delegates resolution to a dedicated TypeScript configuration resolver that translates these aliases into concrete file system paths according to the rules defined in your [`tsconfig.json`](https://github.com/tirth8205/code-review-graph/blob/main/tsconfig.json).

## How the TypeScript Resolver Works

The resolution logic lives in [`code_review_graph/tsconfig_resolver.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/tsconfig_resolver.py) and executes in five distinct phases to handle the complexity of TypeScript's module resolution strategy.

### Loading the Nearest Configuration

The process begins with **`_load_tsconfig_for_file`**, which walks up the directory tree from the importing file until it discovers a [`tsconfig.json`](https://github.com/tirth8205/code-review-graph/blob/main/tsconfig.json) or [`tsconfig.app.json`](https://github.com/tirth8205/code-review-graph/blob/main/tsconfig.app.json). The resolver caches these lookups per directory to avoid redundant filesystem operations on subsequent imports.

### Parsing and Extending Configurations

Once located, the **`_parse_tsconfig`** method reads the JSON (including support for JSONC comments) and recursively resolves any `extends` chain via **`_resolve_extends`**. This ensures that inherited `baseUrl` and `paths` settings from parent configurations merge correctly with local overrides.

### Extracting Resolution Parameters

After merging inherited options, the resolver extracts **`baseUrl`** and the alias map from **`paths`**. These parameters define the root directory for resolution and the pattern mappings that translate alias prefixes to relative subdirectories.

### Pattern Matching and Resolution

The public entry point **`resolve_alias(import_str, file_path)`** receives the raw import string and the absolute path of the file containing it. It combines the `tsconfig` directory with `baseUrl` to form the absolute base directory, then matches the import against each pattern in the `paths` map.

### Filesystem Probing

For each candidate path produced by pattern matching, **`_match_and_probe`** checks a list of extensions in priority order: `.ts`, `.tsx`, `.js`, `.jsx`, and `.vue`. The resolver returns the first existing file it finds, or **`None`** if all candidates fail, leaving the import unresolved in the final graph.

## Integration with the Generic Parser

The parser in [`code_review_graph/parser.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/parser.py) invokes the resolver whenever it encounters non-relative imports in JavaScript or TypeScript files. The integration point appears in the `_do_resolve_module` method:

```python

# code_review_graph/parser.py – lines 1334-1360

elif language in ("javascript", "typescript", "tsx", "vue"):
    if module.startswith("."):
        # …relative handling…

    else:
        # Non‑relative import — try tsconfig path alias resolution

        resolved = self._tsconfig_resolver.resolve_alias(module, file_path)
        if resolved:
            return resolved

```

When the resolver returns a valid path, the graph creates an `IMPORTS_FROM` edge pointing to that specific file. If resolution fails, the edge points to the raw module name, preserving the import relationship without filesystem validation.

## Setting Up tsconfig.json Aliases

To enable alias resolution in your project, configure the `compilerOptions` section of your TypeScript configuration:

1. **Create or edit** [`tsconfig.json`](https://github.com/tirth8205/code-review-graph/blob/main/tsconfig.json) (or [`tsconfig.app.json`](https://github.com/tirth8205/code-review-graph/blob/main/tsconfig.app.json)) at the project root or in an ancestor directory of your source files.

2. **Define `baseUrl`** and **`paths`**:

```json
{
  "compilerOptions": {
    "baseUrl": "src",
    "paths": {
      "@/utils/*": ["utils/*"],
      "@/components/*": ["components/*"]
    }
  }
}

```

3. **Ensure patterns end with `/*`** to match the resolver's glob implementation, which strips the wildcard and appends the corresponding portion of the import path.

## Example: Resolving an Alias in Practice

Consider a project where [`src/app/main.ts`](https://github.com/tirth8205/code-review-graph/blob/main/src/app/main.ts) contains the following imports:

```typescript
import { foo } from "@/utils/foo";
import { Bar } from "@/components/bar";

```

When [`parser.py`](https://github.com/tirth8205/code-review-graph/blob/main/parser.py) processes this file, it invokes:

```python
self._tsconfig_resolver.resolve_alias("@/utils/foo", "/abs/path/src/app/main.ts")

```

The resolver executes the following sequence:

- Loads [`/abs/path/tsconfig.json`](https://github.com/tirth8205/code-review-graph/blob/main//abs/path/tsconfig.json) using `_load_tsconfig_for_file`
- Builds the base directory `/abs/path/src` from `baseUrl`
- Matches `@/utils/*` → `utils/*` and constructs `/abs/path/src/utils/foo`
- Probes for [`/abs/path/src/utils/foo.ts`](https://github.com/tirth8205/code-review-graph/blob/main//abs/path/src/utils/foo.ts) (or [`.tsx/.js/.jsx/.vue`](https://github.com/tirth8205/code-review-graph/blob/main/.tsx/.js/.jsx/.vue))

Upon finding the file, the graph records an **`IMPORTS_FROM`** edge from [`main.ts`](https://github.com/tirth8205/code-review-graph/blob/main/main.ts) to [`utils/foo.ts`](https://github.com/tirth8205/code-review-graph/blob/main/utils/foo.ts), enabling accurate dependency analysis and blast-radius calculations.

## Testing the Implementation

The repository includes a comprehensive test suite to verify alias resolution behavior. Run the tests using pytest:

```bash
pytest tests/test_tsconfig_resolver.py

```

Key test cases include:

- **`test_resolve_alias`** – Verifies successful resolution of valid aliases like `@/lib/utils`
- **`test_resolve_alias_nonexistent_returns_none`** – Confirms `None` is returned for missing target files
- **`test_resolve_npm_package_returns_none`** – Ensures npm package names (e.g., `react`) are not treated as path aliases
- **`test_no_tsconfig_returns_none`** – Validates graceful handling when no configuration file exists in the directory tree
- **`test_caching`** – Confirms that repeated lookups for the same directory use cached results

## Summary

- **Resolution starts in [`code_review_graph/tsconfig_resolver.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/tsconfig_resolver.py)**, which handles the complete lifecycle from configuration discovery to filesystem probing.
- **`_load_tsconfig_for_file`** walks up the directory tree and caches results, while **`_resolve_extends`** handles configuration inheritance with JSONC support.
- The **`resolve_alias`** method matches import strings against `paths` patterns and checks multiple extensions (`.ts`, `.tsx`, `.js`, `.jsx`, `.vue`) to locate the target file.
- **[`code_review_graph/parser.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/parser.py)** automatically invokes the resolver for all non-relative imports in JavaScript, TypeScript, TSX, and Vue files.
- Proper configuration requires `baseUrl` and `paths` entries ending with `/*` wildcards to enable correct pattern substitution.

## Frequently Asked Questions

### What happens if no tsconfig.json file exists?

The resolver returns **`None`** immediately, and the parser records the import using the raw module string rather than a filesystem path. This behavior ensures the graph builds successfully even for projects without TypeScript configuration, though dependency edges will lack precise file resolution.

### Does the resolver support monorepos with multiple tsconfig files?

Yes. The **`_load_tsconfig_for_file`** method locates the nearest configuration by walking upward from each importing file, allowing different packages in a monorepo to use distinct `baseUrl` and `paths` settings. The directory-level cache ensures that files within the same directory reuse the same configuration instance.

### How does the resolver distinguish between npm packages and path aliases?

The resolver attempts resolution for all non-relative imports, but npm packages fail the pattern matching phase because they do not match any keys in the `paths` map. Consequently, **`test_resolve_npm_package_returns_none`** verifies that imports like `react` or `lodash` correctly return `None`, allowing the parser to treat them as external dependencies rather than internal aliases.

### Why does my alias resolve to None despite correct configuration?

Common causes include missing wildcard suffixes in the `paths` entry (the resolver requires `/*` to match dynamic path segments), incorrect `baseUrl` relative to the [`tsconfig.json`](https://github.com/tirth8205/code-review-graph/blob/main/tsconfig.json) location, or missing file extensions. The resolver probes for `.ts`, `.tsx`, `.js`, `.jsx`, and `.vue` files, but if none exist at the constructed path, it returns `None` as implemented in **`_match_and_probe`**.