9

In short: is there a way to know if a typescript parameter is required and/or has a default value?

Longer version: Say I have the following file:

//Foo.ts
class Bar {
    foo(required:string,defaultValue:number=0,optional?:boolean) {
        ...
    }
}

I would like to know of each of the parameters:

  • the name
  • the type
  • is it required?
  • does it have a default value?

I have succesfully used method decorators with the TypeScript reflection API to get the types of the parameters, I've used this method to get their names, but so far I have not found a way to know if a variable is required and/or has a default value.

I know the typescript compiler itself can be used from within typescript. So I'm wondering if there is a way to use the parse tree of the compiler to see if a parameter is required and/or has a default value?

How would that work?

Community
  • 1
  • 1
Flion
  • 10,468
  • 13
  • 48
  • 68
  • 1
    In case you're interested, I have been working on this: https://github.com/dsherret/ts-type-info. At the time I'm writing this it's unstable and subject to change drastically. It does everything you want except right now it only says if the parameter is optional—doesn't specify if that optional is a default value or not, but I can easily add that soon. – David Sherret Jan 09 '16 at 18:21
  • nice! indeed looks exactly what I'm after. Will try to get this working soon. Yes adding default value in the output would be really nice – Flion Jan 09 '16 at 20:00
  • I added `defaultExpression` to it. See my answer below. – David Sherret Jan 10 '16 at 03:33

1 Answers1

6

If you want to do this from scratch...

On a high level, one way of doing it is to:

  1. Figure out how to get the SourceFile node using the compiler api of your file. That requires a bit of an explanation in itself.

  2. From there, use the api's forEachChild function to loop over all the nodes in the file and find the node with a kind of SyntaxKind.ClassDeclaration and .name property with text Bar.

  3. Then loop over all the children of the class by again using the api's forEachChild function and get the ones that has the kind SyntaxKind.MethodDeclaration and .name property with text foo.

  4. To get the parameters, you will need to loop over the method node's parameters property.

  5. Then for each parameter node, to get the name you can call .getText() on the .name property.

  6. You can tell if the parameter is optional by doing:

     const parameterDeclaration = parameterNode as ts.ParameterDeclaration;
     const isOptional = parameterDeclaration.questionToken != null || parameterDeclaration.initializer != null || parameterDeclaration.dotDotDotToken != null;
    

    Or you could use the TypeChecker's isOptionalParameter method.

  7. To get its default expression, you will just have to check the initializer property:

     propertyDeclaration.initializer;
    
  8. To get the type use the TypeChecker's getTypeOfSymbolAtLocation method and pass in the symbol of the node... that gets a little bit complicated so I won't bother explaining it (think about how it's different with union types and such).

Don't do it from scratch...

I've created a wrapper around the TypeScript compiler api. Just use this code with ts-simple-ast (edit: Previously this talked about my old ts-type-info library, but ts-simple-ast is much better):

import { Project } from "ts-morph";

// read more about setup here:
// https://ts-morph.com/setup/adding-source-files
const project = new Project({ tsConfigFilePath: "tsconfig.json" });
const sourceFile = project.getSourceFileOrThrow("src/Foo.ts");
const method = sourceFile.getClassOrThrow("Bar").getInstanceMethodOrThrow("foo");

Once you have the method, it's very straightforward to get all the information you need from its parameters:

console.log(method.getName()); // foo

for (const param of method.getParameters()) {
    console.log(param.getName());
    console.log(param.getType().getText());
    console.log(param.isOptional());
    console.log(param.getInitializer() != null);
}
Bradley
  • 2,071
  • 2
  • 21
  • 32
David Sherret
  • 101,669
  • 28
  • 188
  • 178
  • excelent. thank you for the torough explanation. I was starting to discover exactly all those steps and figured it was going to take quite some effort, so I'm very happy to find your library. Im surprised it's not more known, as far as I can tell it is the best typescript reflection api out there. – Flion Jan 11 '16 at 16:24
  • @Flion thanks, well i haven't told anyone about it until this thread because I wanted it to be more stable first. It still needs a few more weeks of work :) – David Sherret Jan 11 '16 at 18:19