Hone logo
Hone
Problems

Zygohistomorphic Prepromorphisms in TypeScript

This challenge explores a niche concept from category theory – zygohistomorphic prepromorphisms. While the term itself is deliberately obscure, the underlying problem involves creating a data structure and functions that mimic a simplified version of this concept, focusing on the core idea of mapping between related data structures while preserving certain structural properties. This exercise aims to test your understanding of TypeScript's type system, generics, and functional programming principles.

Problem Description

You are tasked with creating a TypeScript implementation of a zygohistomorphic prepromorphism. Essentially, you need to define a function that takes two data structures, Source and Target, and transforms instances of Source into instances of Target. The key constraint is that the transformation must respect a predefined "relationship" between the structures, represented by a mapping function. This mapping function dictates how properties from the Source should be used to construct the Target.

Specifically, you need to:

  1. Define Types: Create generic types Source, Target, and Mapping. Source and Target represent the input and output data structures, respectively. Mapping is a function that takes a Source object and returns a partial object of type Target. This partial object represents the properties of the Target that can be derived from the Source.

  2. Implement zygohistomorphicPrepromorphism Function: This function should accept:

    • source: An instance of Source.
    • mapping: A function of type Mapping.
    • defaultTarget: An object of type Target that provides default values for properties not derived from the Source.

    The function should return an instance of Target constructed as follows:

    • Use the mapping function to extract properties from the source object.
    • Merge the result of the mapping function with the defaultTarget object. If a property exists in both, the value from the mapping function should take precedence.
  3. Handle Missing Properties: The mapping function might not provide values for all properties of the Target. The defaultTarget object should provide sensible default values for these missing properties.

Examples

Example 1:

interface Source1 {
  id: number;
  name: string;
}

interface Target1 {
  sourceId: number;
  displayName: string;
  createdAt: Date;
}

const mapping1 = (source: Source1) => ({
  sourceId: source.id,
  displayName: source.name,
});

const defaultTarget1 = {
  createdAt: new Date(),
};

// Input:
const source: Source1 = { id: 123, name: "Example Name" };
const mapping: (source: Source1) => Partial<Target1> = mapping1;
const defaultTarget: Target1 = defaultTarget1;

// Output:
// { sourceId: 123, displayName: "Example Name", createdAt: Date }
// Explanation: The mapping function extracts 'id' and 'name' from the source.
// 'createdAt' is taken from the defaultTarget.

Example 2:

interface Source2 {
  value: string;
}

interface Target2 {
  processedValue: string;
  originalValue: string;
  isValid: boolean;
}

const mapping2 = (source: Source2) => ({
  processedValue: source.value.toUpperCase(),
});

const defaultTarget2 = {
  originalValue: "",
  isValid: false,
};

// Input:
const source: Source2 = { value: "lowercase" };
const mapping: (source: Source2) => Partial<Target2> = mapping2;
const defaultTarget: Target2 = defaultTarget2;

// Output:
// { processedValue: "LOWERCASE", originalValue: "", isValid: false }
// Explanation: The mapping function only provides 'processedValue'.
// 'originalValue' and 'isValid' are taken from the defaultTarget.

Constraints

  • Source, Target, and Mapping types must be generic.
  • The mapping function must be a function that accepts a Source object and returns a Partial<Target> object.
  • The defaultTarget object must be of type Target.
  • The returned object must be of type Target.
  • The function should be type-safe and avoid runtime errors related to property access.
  • The solution should be reasonably performant for typical data structure sizes (e.g., objects with 10-20 properties).

Notes

  • Consider using the spread operator (...) or object.assign() to merge the results of the mapping function and the defaultTarget object.
  • The term "zygohistomorphic prepromorphism" is intentionally abstract. Focus on the core concept of mapping between data structures while respecting a predefined relationship.
  • Think about how to ensure type safety when merging the two objects. Partial<Target> is crucial here.
  • This problem is designed to test your understanding of TypeScript's type system and your ability to work with generics and functional programming concepts.
Loading editor...
typescript