Hone logo
Hone
Problems

TypeScript Module Resolution Type System

This challenge focuses on building a robust type system for module resolution in TypeScript. Understanding how modules are resolved is crucial for writing maintainable and type-safe JavaScript/TypeScript applications. This exercise will deepen your understanding of TypeScript's type inference and utility types.

Problem Description

Your task is to create a set of TypeScript types that accurately represent the possible outcomes of a module resolution process. This includes handling different types of modules (e.g., built-in Node.js modules, absolute file paths, relative file paths, package names) and their corresponding resolution results.

Key Requirements:

  1. Represent Different Module Types: Create types to distinguish between various module import syntaxes.
  2. Represent Resolution Outcomes: Define types to accurately reflect what a module might resolve to. This could be a specific module object, a file path, or indicate that a module was not found.
  3. Type Safety: Ensure that the resolution types are strongly typed, preventing runtime errors by catching incorrect assumptions about module resolution at compile time.
  4. Extensibility: The design should be reasonably extensible to accommodate future module resolution strategies or environments.

Expected Behavior:

Given a hypothetical module identifier (a string representing an import path or name), your types should be able to describe the potential results of resolving that identifier.

Edge Cases:

  • Modules that might not exist.
  • Different kinds of module identifiers (e.g., @scope/package, package, ./local, /absolute).

Examples

Example 1: Resolving a Relative Path Module

Input: './utils/helpers'
Output: { type: 'file', path: '/path/to/your/project/utils/helpers.ts' } | { type: 'file', path: '/path/to/your/project/utils/helpers/index.ts' } | { type: 'not_found' }
Explanation: A relative path like './utils/helpers' could resolve to a direct file (e.g., utils/helpers.ts) or an index file within a directory (e.g., utils/helpers/index.ts). If neither is found, it's 'not_found'. The 'path' property would contain the resolved absolute path.

Example 2: Resolving a Package Module

Input: 'react'
Output: { type: 'package', name: 'react', version: '18.2.0' } | { type: 'not_found' }
Explanation: Importing a package like 'react' typically resolves to an entry within the 'node_modules' directory. The output indicates the package name and potentially its resolved version. If the package isn't installed or discoverable, it's 'not_found'.

Example 3: Resolving a Built-in Node.js Module

Input: 'fs'
Output: { type: 'builtin', name: 'fs' }
Explanation: Built-in Node.js modules like 'fs' or 'path' have a distinct resolution. They are always available and are represented by their name.

Constraints

  • The input module identifier will always be a string.
  • The primary focus is on creating types to represent resolution, not a runtime module resolver function.
  • The types should be clear and easy to understand.

Notes

  • Consider using discriminated unions to represent the different resolution outcomes.
  • Think about how you would model the information associated with each type of resolution (e.g., path for files, name and version for packages).
  • This challenge is about modeling the potential outcomes, not necessarily implementing a full-fledged Node.js module resolver.
  • You can assume standard Node.js module resolution conventions as a basis.
Loading editor...
typescript