Somehow I lost track of this question while actually finding an interesting solution. It's prettier, doesn't affect interface and doesn't pollute the IDE's list of suggestions.
export type Miles = number & { readonly '': unique symbol };
export type Kilograms = number & { readonly '': unique symbol };
export type MilesPerKilogram = number & { readonly '': unique symbol };
var miles: Miles = 3; // error
var kilos: Kilograms = 3; // error
var milesPerKilos: MilesPerKilogram = x / y; // error
var x: Miles = 3 as Miles; // ok
var y: Kilograms = 3 as Kilograms; // ok
var u: MilesPerKilogram = x / y as MilesPerKilogram; // ok
miles = kilos; // error, yey!
kilos = miles; // error, yey!
Works on any types
Edit
Be careful as you are not allowed to extract { readonly '': unique symbol }
part into separate type as it would share unique symbol across the types and make them share "nominality" which would beat the purpose of a nominal type:
export type Nominal<T> = T & { readonly '': unique symbol };
export type Miles = Nominal<number>;
export type Kilograms = Nominal<number>;
export type MilesPerKilogram = Nominal<number>;
var miles: Miles = 3; // error
var kilos: Kilograms = 3; // error
var milesPerKilos: MilesPerKilogram = x / y; // error
var x: Miles = 3 as Miles; // ok
var y: Kilograms = 3 as Kilograms; // ok
var u: MilesPerKilogram = x / y as MilesPerKilogram; // ok
miles = kilos; // ok, but it should be error! <================= This is due to declaration of Nominal<T>
Consider also https://basarat.gitbook.io/typescript/main-1/nominaltyping for more info