tyflow
v0.1.0
Published
Utility function to map a value to a function
Downloads
5
Maintainers
Readme
tyflow
The tyflow utility function is used to create a function that maps an object to a specific handler based on a discriminator path.
To illustrate better how it works imagine we had the following types:
interface Person<T extends Vehicle> {
name: string;
age: number;
vehicle: T;
}
type Vehicle = Car | Bike;
interface Car {
details: {
type: "car";
fuel: "electric" | "gas";
model: string;
year: number;
};
performance: {
horsepower: number;
topSpeed: number; // in km/h
};
}
interface Bike {
details: {
type: "bike";
gear: "fixed" | "multi";
brand: string;
};
specifications: {
weight: number; // in kg
frameMaterial: string;
};
}If we wanted to create a function called generateMessage that receives a person as
argument and returns different data depending on the vehicle that the person has we
could use the tyflow function the following way:
import { tyflow } from "tyflow";
interface Person<T extends Vehicle> {
name: string;
age: number;
vehicle: T;
}
type Vehicle = Car | Bike;
interface Car {
details: {
type: "car";
fuel: "electric" | "gas";
model: string;
year: number;
};
performance: {
horsepower: number;
topSpeed: number; // in km/h
};
}
interface Bike {
details: {
type: "bike";
gear: "fixed" | "multi";
brand: string;
};
specifications: {
weight: number; // in kg
frameMaterial: string;
};
}
interface Tyflow {
object: Person<Vehicle>;
nested: ["vehicle"];
filter: ["details", "type"];
params: [];
return: string;
}
const dispatch = tyflow<Tyflow>(["vehicle"], ["details", "type"], {
car: (person: Person<Car>) => {
return `This person drives a ${person.vehicle.details.fuel} car.`;
},
bike: (person: Person<Bike>) => {
return `This person rides a ${person.vehicle.details.gear} bike.`;
},
});
function generateMessage(person: Person<Vehicle>): string {
return dispatch(person);
}
const personWithCar: Person<Car> = {
name: "John",
age: 25,
vehicle: {
details: {
type: "car",
fuel: "gas",
model: "Toyota Corolla",
year: 2020,
},
performance: {
horsepower: 132,
topSpeed: 180,
},
},
};
console.log(generateMessage(personWithCar)); // This person drives a gas car.The type that the function receives is an object with the following properties:
object: The input object.nested: The path to the property that contains the union to be narrowed.filter: The path to the discriminator key within the union.params: Extra arguments to pass to the returned function.return: The return type of the returned function.
The function parameters that the function receives are the following:
- The path to the property that contains the union to be narrowed.
- The path to the discriminator key within the union.
- A map of discriminator values to handler functions that handle narrowed types.
Refine utility type
If the Person type was not generic we would need to use the Refine utility type:
import { tyflow, type Refine } from "tyflow";
interface Person {
name: string;
age: number;
vehicle: Vehicle;
}
type Vehicle = Car | Bike;
interface Car {
details: {
type: "car";
fuel: "electric" | "gas";
model: string;
year: number;
};
performance: {
horsepower: number;
topSpeed: number; // in km/h
};
}
interface Bike {
details: {
type: "bike";
gear: "fixed" | "multi";
brand: string;
};
specifications: {
weight: number; // in kg
frameMaterial: string;
};
}
type PersonWithCar = Refine<{
object: Person;
nested: ["vehicle"];
filter: ["details", "type"];
narrow: "car";
}>;
type PersonWithBike = Refine<{
object: Person;
nested: ["vehicle"];
filter: ["details", "type"];
narrow: "bike";
}>;
interface Tyflow {
object: Person;
nested: ["vehicle"];
filter: ["details", "type"];
params: [];
return: string;
}
const dispatch = tyflow<Tyflow>(["vehicle"], ["details", "type"], {
car(person: PersonWithCar) {
return `This person drives a ${person.vehicle.details.fuel} car.`;
},
bike(person: PersonWithBike) {
return `This person rides a ${person.vehicle.details.gear} bike.`;
},
});
function generateMessage(person: Person): string {
return dispatch(person);
}
const personWithCar: PersonWithCar = {
name: "John",
age: 25,
vehicle: {
details: {
type: "car",
fuel: "gas",
model: "Toyota Corolla",
year: 2020,
},
performance: {
horsepower: 132,
topSpeed: 180,
},
},
};
console.log(generateMessage(personWithCar)); // This person drives a gas car.