Monorepo Type System Generator
Building and maintaining large TypeScript projects often involves multiple packages sharing common types and interfaces. A monorepo architecture, where multiple packages reside within a single repository, amplifies this need for shared type definitions. This challenge asks you to create a utility that generates a simplified type definition file (shared.d.ts) from a list of package names, inferring common types based on a provided set of interfaces.
Problem Description
You are tasked with creating a TypeScript function generateSharedTypes that takes an array of package names and an object containing interface definitions as input. The function should analyze the provided interfaces and generate a shared.d.ts file content string. This file will contain a merged declaration of all interfaces, ensuring type safety across the monorepo.
What needs to be achieved:
- Parse a list of package names.
- Analyze a provided object of interface definitions.
- Generate a
shared.d.tsfile content string containing merged interface declarations. - Handle potential naming conflicts gracefully (e.g., by prefixing conflicting interface names with the package name).
Key Requirements:
- The generated
shared.d.tsfile should be valid TypeScript. - All interfaces provided in the input object should be included in the output.
- If multiple interfaces have the same name, the function should prefix the conflicting interfaces with the package name that owns them to avoid errors.
- The function should be robust and handle edge cases such as empty input arrays or empty interface objects.
Expected Behavior:
The function should return a string representing the content of the shared.d.ts file. This string should contain the merged interface declarations, properly formatted and ready to be written to a file.
Edge Cases to Consider:
- Empty package name array.
- Empty interface object.
- Multiple interfaces with the same name originating from different packages.
- Complex interface structures (nested interfaces, unions, intersections).
- Invalid interface definitions (though the function doesn't need to validate the interfaces, it should handle them gracefully without crashing).
Examples
Example 1:
Input: packageNames = ["packageA", "packageB"], interfaces = {
"packageA": {
"User": { id: number, name: string }
},
"packageB": {
"User": { email: string, isAdmin: boolean }
}
}
Output:
```typescript
// shared.d.ts
interface packageAUser {
id: number;
name: string;
}
interface packageBUser {
email: string;
isAdmin: boolean;
}
Explanation: Two interfaces named "User" exist, one from "packageA" and one from "packageB". They are both included in the output, prefixed with their respective package names.
Example 2:
Input: packageNames = ["packageC"], interfaces = {
"packageC": {
"Product": {
id: string;
price: number;
description: string;
}
}
}
Output:
```typescript
// shared.d.ts
interface packageCProduct {
id: string;
price: number;
description: string;
}
Explanation: A single interface "Product" exists within "packageC". It is included in the output, prefixed with "packageC".
Example 3: (Edge Case)
Input: packageNames = [], interfaces = {}
Output:
```typescript
// shared.d.ts
Explanation: Both the package names array and the interfaces object are empty. The output is an empty file.
Constraints
packageNamesis an array of strings, each representing a package name.interfacesis an object where keys are package names (matching those inpackageNames) and values are objects containing interface definitions. Interface definitions are standard TypeScript interface objects.- Package names are non-empty strings.
- The generated
shared.d.tsfile content string should be a valid TypeScript declaration file. - The function should complete within a reasonable time (e.g., less than 1 second) for a monorepo with up to 100 packages and 50 interfaces per package.
Notes
- Consider using template literals to construct the
shared.d.tsfile content string. - Pay close attention to the naming conventions and how to handle naming conflicts.
- The focus is on generating the content of the file, not writing it to disk.
- You don't need to implement any sophisticated type inference or merging beyond simply concatenating the interface declarations. The goal is to create a basic, functional type system generator.
- Error handling is not required; assume the input is well-formed.