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:
-
Define Types: Create generic types
Source,Target, andMapping.SourceandTargetrepresent the input and output data structures, respectively.Mappingis a function that takes aSourceobject and returns a partial object of typeTarget. This partial object represents the properties of theTargetthat can be derived from theSource. -
Implement
zygohistomorphicPrepromorphismFunction: This function should accept:source: An instance ofSource.mapping: A function of typeMapping.defaultTarget: An object of typeTargetthat provides default values for properties not derived from theSource.
The function should return an instance of
Targetconstructed as follows:- Use the
mappingfunction to extract properties from thesourceobject. - Merge the result of the
mappingfunction with thedefaultTargetobject. If a property exists in both, the value from the mapping function should take precedence.
-
Handle Missing Properties: The
mappingfunction might not provide values for all properties of theTarget. ThedefaultTargetobject 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, andMappingtypes must be generic.- The
mappingfunction must be a function that accepts aSourceobject and returns aPartial<Target>object. - The
defaultTargetobject must be of typeTarget. - 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 themappingfunction and thedefaultTargetobject. - 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.