type Eq<A, B> = <X>(a: A, eq: (x: A & B) => X) => X;
const refute = (x: never) => x;
const refl = <A, X>(a: A, eq: (x: A) => X) => eq(a);

const sickos = <A>(x: A, eq: Eq<A, number>) => eq(x, (x) => x);
const two = sickos(2, refl);

type Ty<A> =
  | { tag: "number"; eq: Eq<A, number> }
  | { tag: "string"; eq: Eq<A, string> };
const number: Ty<number> = { tag: "number", eq: refl };
const string: Ty<string> = { tag: "string", eq: refl };
const show_number_or_string = <A>(x: A, ty: Ty<A>) => {
  if (ty.tag === "number") {
    return ty.eq(x, (x) => `number: ${x.toString()}`);
  } else if (ty.tag === "string") {
    return ty.eq(x, (x) => `string: ${x}`);
  } else {
    return refute(ty);
  }
};

const printed_number = show_number_or_string(2, number);
console.log(printed_number);

const printed_string = show_number_or_string("a", string);
console.log(printed_string);