Typescript: Implementing a transformer to access types at run-time

Viewed 377

After TSC compiled the TS code to JS, the types are removed and not available anymore.

But, in principle, it should be possible to make the types available at run-time by using a webpack/typescript/Vite transformer.

Has anyone achieved this?

type Data = {
  name: string;
  age: number;
};

// How can we implement `getType()`?
console.log(getType<Data>());
// It should print:
// { name: 'string', age: 'number' }

At compile-type, the type of Data is known, so it should be possible (albeit not easy) to implement a transformer that makes the type available at run-time.

This would enable a mirad of uses cases, such as IO validation.

For my use case I don't need advanced types such as generics. I only need the types: object, array, string, number, and date.

Context: I'm building an RPC implementation (https://github.com/brillout/wildcard-api).

Edit: I'm not looking for something like zod where you define a schema with zod and the TypeScript types are then inferred. My users define their types with TypeScript directly and I need to know these types at run-time. So I do need a compile-time transformer.

3 Answers

Is something like ts-runtime what you are after? It's not exactly as your question describes but have a look at this.

Your input code:

type Data = {
  name: string;
  age: number;
};

It outputs:

import t from "ts-runtime/lib";

const Data = t.type(
  "Data",
  t.object(
    t.property("name", t.string()),
    t.property("age", t.number())
  )
);

You can then run:

t.type(Data).assert({/* ... obj to evaluate ... */})

The typescript-rtti project does this comprehensively for all type metadata for a given compilation (and works across packages when both the caller and the callee have been compiled using the transformer). You can test it out from the browser at https://typescript-rtti.org/

(Disclaimer: I am the author)

Try tst-reflect. It is pretty advanced Reflection system for TypeScript, inspired by the C# reflection.

import { getType, Type } from "tst-reflect";

type Data = {
  name: string;
  age: number;
};

const typeofData: Type = getType<Data>();

const objWithProps = typeofData.getProperties().reduce((res, prop) => {
  res[prop.name] = prop.type.name;
  return res;
}, {} as any);

console.log(objWithProps);

Output

{ name: 'String', age: 'Number' }
Related