Query Type Information from within TypeScript

Topics: General
Sep 20, 2013 at 7:11 PM

I'm wondering if there's currently any supported way to query the type information about user-generated interfaces/classes/etc from within TypeScript itself.

It looks like the "services" code in the TypeScript distribution provides some of this, but it's mostly geared for providing tooling. I'm more interested in "reflection-like" capabilities, although it doesn't really need to be reflection in the sense of runtime type information, and I'm aware that the language team doesn't want to add anything that would degrade the resulting JS files (like "proper/runtime" reflection). Compile/build type support would be sufficient.

Maybe something analogous to the compiler emitting a declarations (.d.ts)-like file that generated real JS objects that could be used within JS/TypeScript? I'm sure I could write a parser/preprocessor step for this myself, but I don't want to reinvent anything if it's already available, etc.

Sep 23, 2013 at 11:19 PM
I'm not sure I'm following what exactly you want. Can you describe what you're trying to accomplish that isn't traditional JavaScript style reflection or akin to the language service/compiler APIs asking for type information?
Sep 24, 2013 at 4:06 AM
Edited Sep 24, 2013 at 4:12 AM
You're right in that I'm asking about capabilities that are akin to the language services, specifically retrieving the type hints for a specified class/interface, etc.

I browsed through the "Services" code, and from what I can tell it's really geared towards tooling (eg, it seems to have a heavy emphasis on querying given a POSITION in a file instead of a specific TYPE name). What I would like is the ability to query by class/interface/type name instead. I think I could achieve what I want by have some build-time step to translate the generated *.d.ts files to .js files containing JSON representations for them. I just wanted to make sure that there isn't a more "supported" or "acceptable" solution.
Sep 24, 2013 at 9:01 AM
We have a similar requirement, namely to generate concrete JavaScript objects from interface declarations, so that they can be used for testing.

I opened a ticket for this some time ago and it got an "assigning to X or Y who handles suggestions" (which I believe in internal TS speak means "ignore"!).

I can also see further use-cases, for instance for use in runtime dependency injection.

We'd really like to see some support for this.

Note that this is certainly not about a TypeScript runtime at all, rather it is about generating JavaScript files for some of the information that the compiler strips away and discards.
Sep 24, 2013 at 11:09 AM
Edited Sep 24, 2013 at 11:29 AM
If only this Typescript code
module foo{
    export class A{
        public x1:number = 10;
        public x2 = 20;
        public s1: string = "";

var typeName      = getType(foo.A).getName();
var numericFields = getType(foo.A)
                    .filter(f=> f.getType() == numeric)
                    .map(f=> f.getName());
could be compiled to something like this:
var foo;
(function (foo) {
    var A = (function () {
        function A() {
            this.x1 = 10;
            this.x2 = 20;
            this.s1 = "";
        return A;
    foo.A = A;
})(foo || (foo = {}));

var typeName = "foo.A";
var numericFields = ["x1", "x2"];
that would be really cool, I think.
Here function "getType" exists only in compile time and emits type information as JS objects.
Sep 24, 2013 at 11:18 AM
That will generate quite a bit of metadata that needs to be pushed over the wire to clients.
Most of this data will never be used by anyone.

I do love reflection, but I doubt you will see this in TypeScript for the above reason.
Sep 25, 2013 at 4:14 AM
Yes, the examples that prohazko gave illustrate my original request very well, and would add basically no overhead to the generated JS (something that I know is a design goal). It keeps all of the new functionality strictly as build-time compiler steps and the code gets stripped away to the bare CONSTANTS that can easily be processed at runtime.

I definitely give this concept a "+1" in case any of the language designers are listening!
Oct 13, 2013 at 11:02 PM
We could define a meta-data export-annotation for this?

A new context keyword maybe, or something comment-based, like the references.

You'd put it before the line of the type for which you want to export meta-data, so you can control what is exported.
/// <describe-type>
interface MyType  {
It'd create a little object structure describing all the type info and export it (somewhere without runtime dependencies.. but where?). It'd be nice if it could refer to other exported types (if applicable).

Somebody with time to spend could venture to do this externally and use the TypeScript parser to get a source-tree and walk the nodes.

Find the annotations, transform the local data and export as JSON somewhere it can be loaded again. Or maybe do it a pre-processor to generate (typed) code to get compiled into the main code unit, that could be cool (meta-codeception :D).

Bonus-points if it can do json-schema.

Almost same thing right? Put some more detailed validation annotations in the code, export to details schemas and use existing schema validators on your objects during testing. Also use json-schema based stub/mock generators.

If I didn't had have a big project already I'd go for it. For inspiration look at TSLint (different thing but also a TypeScript tree walker).
Oct 14, 2013 at 9:04 AM
just wanted to note that prohazko's example is within the limits of the JS reflection system (only JS types, all properties initialized; nothing bad happening in the constructor):
module foo{
    export class A{
        public x1:number = 10;
        public x2 = 20;
        public s1: string = "";
        constructor(public x = true) {}

function listProperties(o, isClass?) {
    var props = [];
    var tmp = isClass ? new o : o;
    for (var p in tmp)
      console.log(p,typeof tmp[p]);
name: A
x boolean
x1 number
x2 number
s1 string
.name is already available (eg, in v8), and is going to be standard in ES6.
Oct 14, 2013 at 9:54 AM
One concrete feature suggestion that would be helpful: a language service method for getting declaration-style information about a type. We can get the type of an expression, we can jump to a definition (which may be an interface declaration or an implementation), we can list completions, but I don't think there is a way to get an interface description.

Currently, the declarationEmitter is part of the compiler, and it works syntactically, by walking a single source file/AST in question. But interfaces can be extended over many modules, and it would be useful to have a semantic query: what is the interface represented by this type name (at this source position in a project).
Oct 14, 2013 at 2:47 PM

The assumption "nothing bad happening in the consctructor" is not very realistic with respect to object oriented code.

It wouldn't be possible to write new o without passing in constructor arguments, and constructing a new object simply to get its meta data seems wrong.

Furthermore this will need to work for interfaces, which is personally my primary requirement, because we would like to mock up TypeScript interfaces for our test harness.

In short, the meta data provision needs to be based on the static analysis of the code - not its runtime representation.

Regarding an output format, my preference is that the meta data should be compiled into a separate file ( a "myproj.meta" file, one file per project) rather than the getType construct that @prohazko suggests.
Oct 14, 2013 at 10:38 PM
As far as tooling goes: language service completions (intellisense support) seem to have most of the information you are asking for. So you could use the language service to make that information available to JS code, by pretending to complete something typed to the interface you are interested in. Or you could employ my typescript-tools project ( https://github.com/clausreinke/typescript-tools ) to get the same information from the commandline, in JSON format.

Taking my code from above, in file reflection.ts, pipe commands into tss (typescript service server) to:
  • add (in memory only) a line (update) to be completed (var XXX:foo.A;XXX.),
  • ask for completions after the dot (completions),
  • slightly reformat the JSON output (sed)
$ (echo "update 1 19-19 reflection.ts";
> echo "var XXX:foo.A;XXX.";
> echo "completions true 19 19 reflection.ts") |
> tss reflection.ts |
> sed 's/,"/,\n"/g'
"loaded c:/javascript/typescript/reflection.ts, TSS listening.."
"updated lines 19-19 in c:/javascript/typescript/reflection.ts, (1/0) errors"
"TSS closing"
Feb 4, 2015 at 10:34 AM

You might find this project interesting: https://github.com/artifacthealth/tsreflect-compiler.
Feb 6, 2015 at 7:33 PM
Edited Feb 6, 2015 at 7:34 PM
Thanks, I'll check that out.

Also worth mentioning is Google's AtScript, which adds runtime type information similar to what I was asking about in my initial question: https://docs.google.com/document/d/11YUzC-1d0V1-Q3V0fQ7KSit97HnZoKVygDxpWzEYW0U/edit