Creating a Tombstone in TypeScript

Viewed 79

I have some values in TypeScript that are only needed within the type system. I'm looking for a way to void the values without forgetting their type. The function bury in the example below is expected to replace the runtime value with undefined and cast it into a tombstone for the buried type. However, my example implementation of Tombstone is not sufficient because Tombstone<{ id: string }> equals void which equals Tombstone<{ id: number }>. What would be a good way to distinguish between buried values? I'd like to avoid confusing developers and wasting runtime memory with values that are only needed for type checking.

type Tombstone<_A> = void
function bury<A>(_value: A): Tombstone<A> {
  return undefined as Tombstone<A>
}

type Item = { id: number }

const correct: Tombstone<Item> = bury({ id: 123 })
const incorrect: Tombstone<Item> = bury({ id: 'abc' })  // <- should not work

type Special = Item & { meta: string }

const correct2: Tombstone<Item> = bury({ id: 123, meta: 'test' })
const correct3: Tombstone<Special> = bury({ id: 123, meta: 'test' })

const incorrect2: Tombstone<Special> = bury({ id: 123 })  // <- should not work
1 Answers

Using a class with a private property seems to work.

class Tombstone<A> {
  // @ts-ignore _a is used to store the type and is never read
  private readonly _a!: A
}

function bury<A>(_value: A): Tombstone<A> {
  return undefined as unknown as Tombstone<A>
}

type Item = { id: number }

const correct: Tombstone<Item> = bury({ id: 123 })
// @ts-expect-error string is not assignable to number
const incorrect: Tombstone<Item> = bury({ id: 'abc' })

type Special = Item & { meta: string }

const correct2: Tombstone<Item> = bury({ id: 123, meta: 'test' })
const correct3: Tombstone<Special> = bury({ id: 123, meta: 'test' })
// @ts-expect-error missing required property 'meta'
const incorrect2: Tombstone<Special> = bury({ id: 123 })
Related