TypeScript Plug'n'Play Resolver

1.2.0 · maintenance · verified Sun Apr 19

ts-pnp provides a low-level module resolver specifically designed to integrate Yarn's Plug'n'Play (PnP) resolution strategy with the TypeScript compiler API. It is primarily intended for developers building custom TypeScript compiler hosts, tools, or plugins, rather than for direct application usage. The current stable version is 1.2.0, indicating a mature and stable API, and its release cadence is generally tied to updates in Yarn PnP or TypeScript APIs. Its key differentiator is enabling seamless PnP support for TypeScript's module resolution, allowing TypeScript projects to leverage the benefits of PnP without complex manual configuration, particularly when used in conjunction with companion plugins for build tools like Webpack, Jest, and Rollup.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart demonstrates how to create a custom TypeScript `CompilerHost` that integrates `ts-pnp` for module and type reference resolution, providing Yarn Plug'n'Play support within a TypeScript compilation pipeline. It shows the core `resolveModuleName` hook implementation with a crucial fallback to TypeScript's default resolvers.

import { resolveModuleName as resolvePnpModuleName } from 'ts-pnp';
import * as ts from 'typescript';

interface CustomCompilerHost extends ts.CompilerHost {
  resolveModuleNames: (moduleNames: string[], containingFile: string) => (ts.ResolvedModule | undefined)[];
  resolveTypeReferenceDirectives: (typeDirectiveNames: string[], containingFile: string) => (ts.ResolvedTypeReferenceDirective | undefined)[];
}

function createPnPCompilerHost(
  compilerOptions: ts.CompilerOptions,
  host?: ts.CompilerHost, // Optional base host for fallback
): CustomCompilerHost {
  // Provide a default host if none is given
  const baseHost = host || ts.createCompilerHost(compilerOptions, true);

  const customHost: CustomCompilerHost = {
    ...baseHost,
    resolveModuleNames,
    resolveTypeReferenceDirectives,
  };

  return customHost;

  function resolveModuleNames(moduleNames: string[], containingFile: string) {
    return moduleNames.map(moduleName => {
      // ts-pnp resolver with a fallback to TypeScript's default resolver
      const resolved = resolvePnpModuleName(
        moduleName,
        containingFile,
        compilerOptions,
        customHost,
        ts.resolveModuleName // Essential fallback to TypeScript's internal resolver
      );
      return resolved.resolvedModule;
    });
  }

  function resolveTypeReferenceDirectives(typeDirectiveNames: string[], containingFile: string) {
    return typeDirectiveNames.map(typeDirectiveName => {
      // ts-pnp resolver for type directives, with fallback
      const resolved = resolvePnpModuleName(
        typeDirectiveName,
        containingFile,
        compilerOptions,
        customHost,
        ts.resolveTypeReferenceDirective // Essential fallback for type reference directives
      );
      return resolved.resolvedTypeReferenceDirective;
    });
  }
}

// Example usage (conceptual, actual compilation would involve more setup):
const compilerOptions: ts.CompilerOptions = {
  target: ts.ScriptTarget.ESNext,
  module: ts.ModuleKind.ESNext,
  strict: true,
  // ... other options
};

const pnpHost = createPnPCompilerHost(compilerOptions);
console.log('PnP-enabled TypeScript CompilerHost created.');
// To compile, you would typically use ts.createProgram with this host:
// const program = ts.createProgram(['./src/index.ts'], compilerOptions, pnpHost);
// program.emit();

view raw JSON →