Hone logo
Hone
Problems

Peer Dependency Resolution in TypeScript

Managing peer dependencies can be tricky, especially when dealing with multiple versions of the same dependency across different packages within a monorepo or multi-package project. This challenge asks you to create TypeScript types that help enforce and resolve peer dependency constraints, ensuring compatibility and preventing version conflicts. This is crucial for maintaining a stable and predictable development environment.

Problem Description

You need to define TypeScript types that represent and resolve peer dependency relationships. The core of the challenge is to create a type that, given a package's peer dependencies and the versions of those dependencies installed in its environment, determines the compatible versions of the peer dependencies. The resolver should handle version ranges (e.g., "1.x.x", ">=2.0.0", "<3.0.0") and return a set of compatible versions.

Key Requirements:

  • PeerDependency Type: Define a type representing a single peer dependency. This type should include the package name (string) and a version range (string). The version range should follow semantic versioning (semver) conventions.
  • PeerDependencies Type: Define a type representing a collection of peer dependencies. This should be a mapping of package name to version range (e.g., { "react": "16.x.x", "lodash": ">=4.0.0" }).
  • InstalledVersion Type: Define a type representing a specific installed version of a package (string).
  • InstalledVersions Type: Define a type representing a collection of installed versions for different packages (e.g., { "react": "16.8.0", "lodash": "4.17.21" }).
  • ResolvePeerDependencies Type: Define a function type that takes a PeerDependencies object and an InstalledVersions object as input and returns an InstalledVersions object. The returned object should contain only the peer dependencies that are actually present in the installed versions. If a peer dependency is not installed, it should not be included in the resolved output.
  • Semver Compatibility: The ResolvePeerDependencies function must correctly determine if an installed version satisfies the version range specified in the peer dependency. You can use a library like semver for this purpose (install it with npm install semver).

Expected Behavior:

The ResolvePeerDependencies function should filter the peer dependencies, keeping only those that have a matching installed version. It should not modify the installed versions themselves; it should only return a subset of them.

Edge Cases to Consider:

  • Empty PeerDependencies object.
  • Empty InstalledVersions object.
  • Version ranges that are very broad (e.g., "x.x.x").
  • Version ranges that are very specific (e.g., "1.2.3").
  • Packages with no peer dependencies.
  • Packages with conflicting peer dependencies (e.g., one peer dependency requiring "react@16.x.x" and another requiring "react@17.x.x"). The resolver should simply return the compatible versions it finds, without attempting to resolve the conflict.

Examples

Example 1:

const peerDependencies: PeerDependencies = {
  react: "16.x.x",
  lodash: ">=4.0.0"
};

const installedVersions: InstalledVersions = {
  react: "16.8.0",
  lodash: "4.17.21",
  express: "4.17.1" // Not a peer dependency
};

// Expected Output:
// { react: "16.8.0", lodash: "4.17.21" }

Explanation: Both react and lodash are peer dependencies and have compatible installed versions. express is not a peer dependency and is therefore excluded.

Example 2:

const peerDependencies: PeerDependencies = {
  react: "17.x.x"
};

const installedVersions: InstalledVersions = {
  react: "16.8.0"
};

// Expected Output:
// {}

Explanation: react is a peer dependency, but the installed version ("16.8.0") does not satisfy the version range "17.x.x". Therefore, the output is an empty object.

Example 3:

const peerDependencies: PeerDependencies = {
  react: ">=16.0.0 <17.0.0"
};

const installedVersions: InstalledVersions = {
  react: "16.9.0",
  react: "16.5.0" // Duplicate key, only the last value matters
};

// Expected Output:
// { react: "16.9.0" }

Explanation: The version range allows versions between 16.0.0 (inclusive) and 17.0.0 (exclusive). "16.9.0" satisfies this range, while "16.5.0" also does. The last installed version for a key is used.

Constraints

  • The version range format should adhere to semantic versioning (semver) conventions.
  • You must use the semver library for version comparison.
  • The solution must be written in TypeScript.
  • The ResolvePeerDependencies function should be efficient enough to handle a reasonable number of peer dependencies (e.g., up to 100).

Notes

  • Consider using generics to make your types more flexible.
  • Think about how to handle different types of version ranges (e.g., exact versions, version ranges, wildcards).
  • The focus is on the type definitions and the logic for resolving peer dependencies, not on error handling or complex build tooling. Assume the input data is valid.
  • The InstalledVersions type should only contain keys that are also present in the PeerDependencies object.
Loading editor...
typescript