Description
When using a functional programming style it is common to have a module that contains a record type, constructor functions for that record type and other function that operate on that type. For example consider a simple module for a date record:
date.ts
export interface Date {
readonly day : number,
readonly month : number,
readonly year : number
};
export function createDate(day: number, month: number, year: number): Date {
return {day, month, year};
}
export function diffDays(date1: Date, date2: Date): number {
// Imagine implementation that calculates
// the difference in days between date1 and date2
}
// Extract the year from the date
export function year(date: Date): number {
return date.year;
}
This works well to start with. However we may at some point want to refactor the structure of the Date
type. Let's say we decide it is better to have it store ticks since epoch:
export interface Date {
readonly ticks : number,
};
The problem is now that other modules may have directly read the Date.years
property instead of going through our year()
function. So other modules are now directly coupled to the type's structure, making our refactoring hard because we need to go through and change all calling modules instead of just changing our date module. (In real-world scenarios the record type is more complex and perhaps nested).
The Ocaml programming language has a nice solution for this called abstract types (see docs here, under the heading "Abstract Types".
The idea is that we export the fact that there is a Date
type and you have to use that type to call our functions. However we do not export the structure of the Date
type. The structure is only known within our date.ts
module.
A suggestion for the syntax could be:
date.ts
export abstract interface Date {
readonly day : number,
readonly month : number,
readonly year : number
};
other.ts
Import { Date, createDate, year } from "./date"
const date = createDate(2017, 1, 1);
const a = year(date); // OK
const b = date.year; // ERROR
Maybe typescript already has a construct for achieving something similar but my research have not found any.