The challenge is that TypeScript’s types only exist at compile time, and all type information is erased after compiling (with a few exceptions like enum). Therefore, there’s no way to change runtime behavior based on type information.
To the best of my knowledge, there are no bundler plugins that can automatically generate default values for TypeScript types as well. One challenge is that TypeScript uses structural typing, which means it cannot distinguish between types that have the same structure. If two types have the same structure but different use cases requiring different default values, it would be impossible to generate distinct default values for each, even with a bundler plugin.
If you have experience with programming languages like Java and Rust, you might notice a similar pattern where an interface or trait is implemented by a class or struct to enable certain functionalities, like the Comparable
interface in Java or the Default
trait in Rust.
You can simulate this in JavaScript by moving the “interface implementation” to an object and manually passing this object (the “externally defined interface implementation”) to a function that needs it. The following example demonstrates this, similar to how “Type classes” are used in fp-ts:
interface Default<T> {
default: T;
}
const getDefault = <T>(d: Default<T>): T => d.default;
const defaultString: Default<string> = {
default: "",
};
const defaultNumber: Default<number> = {
default: 0,
};
interface Point {
x: number;
y: number;
}
const defaultPoint: Default<Point> = {
default: { x: getDefault(defaultNumber), y: getDefault(defaultNumber) },
};
interface Vector {
from: Point;
to: Point;
}
const defaultVector: Default<Vector> = {
default: { from: getDefault(defaultPoint), to: getDefault(defaultPoint) },
};
// ...Somewhere else in the code, such as in React
const [data, setData] = useState({ v1: getDefault(defaultVector), v2: getDefault(defaultVector) });
It might seem odd to use a Default<T>
instead of just T
as the “implementation of a Type class”. In this case, it might not make much sense, but if you want to define more “Type classes” that hold more than one property, such as Monoid
in fp-ts, this paradigm becomes more consistent and universal.