Ts-morph: How to find all the types involved in a node?

Created on 5 Oct 2019  路  5Comments  路  Source: dsherret/ts-morph

How to find all the types involved in a node?

export const TraceConfiguration = {
    register(container?: IContainer): void {
        Object.assign(Tracer, DebugTracer);
    }
};

These types: IContainer, Tracer, DebugTracer for TraceConfiguration node.

or

export type BindingWithBehavior = IBinding & {
    sourceExpression: BindingBehaviorExpression;
};

These types: IBinding, BindingBehaviorExpression for BindingWithBehavior node.

No matter what is the node (Variable, Class, Literal, ...) or where is the type (in Parameter, Block, Union, ... ).

I want to access all available type.getText() in the whole node.

Does exist any general way to find out whole types that are used in a node? or I should define a specific functionality for each use case.

question

Most helpful comment

Oh sorry, I misread your question originally. You may have to do:

const types = new Set<Type>();
node.forEachDescendant(descendant => {
    if (TypeGuards.isTypedNode(descendant) || TypeGuards.isIdentifier(descendant))
        types.add(descendant.getType());
    else if (TypeGuards.isReturnTypedNode(descendant))
        types.add(descendant.getReturnType());
});

That will get implicit types as well. You may want to filter out any types when you're done (check Type#isAny())

All 5 comments

@HamedFathi I think you could just do:

const types = new Set<Type>();
node.forEachDescendant(descendant => {
    if (TypeGuards.isTypeNode(descendant))
        types.add(descendant.getType());
});

// or in 4.2.0 (just released)
const types = new Set<Type>(node.forEachDescendantAsArray().filter(TypeGuards.isTypeNode).map(d => d.getType()));

That won't get all the implicit types in there though.

Side note: Using forEachDescendantAsArray is slightly more efficient than using getDescendants() because getDescendants() will return parsed out token nodes.

That won't get all the implicit types in there though.

May I ask you to give me an example for this?

const types = new Set<Type>(node.forEachDescendantAsArray().filter(TypeGuards.isTypeNode).map(d => d.getType()));

Looks amazing.

Oh sorry, I misread your question originally. You may have to do:

const types = new Set<Type>();
node.forEachDescendant(descendant => {
    if (TypeGuards.isTypedNode(descendant) || TypeGuards.isIdentifier(descendant))
        types.add(descendant.getType());
    else if (TypeGuards.isReturnTypedNode(descendant))
        types.add(descendant.getReturnType());
});

That will get implicit types as well. You may want to filter out any types when you're done (check Type#isAny())

@dsherret

I use your code as the following:

function isNotPrimitiveType(type: Type): boolean {
    return (
        !type.isAny() &&
        !type.isUnknown() &&
        !type.isNull() &&
        !type.isNumber() &&
        !type.isNumberLiteral() &&
        !type.isString() &&
        !type.isStringLiteral() &&
        !type.isBoolean() &&
        !type.isBooleanLiteral()
    );
}

function getUsedTypes(node: Node): Type[] {
    const result: Type[] = [];
    const types = new Set<Type>();
    node.forEachDescendant(descendant => {
        if (TypeGuards.isTypedNode(descendant) 
                || TypeGuards.isIdentifier(descendant)) 
                     types.add(descendant.getType());
        else if (TypeGuards.isReturnTypedNode(descendant)) 
                     types.add(descendant.getReturnType());            
    });
    types.forEach(type => {
        if (isNotPrimitiveType(type)) {
            result.push(type);
        }
    });
    return result;
}

But I got an error on this:

public visitTemplate(expr: AST.TemplateExpression): void {
    const { cooked, expressions } = expr;
    const length = expressions.length;
    this.text += '`';
    this.text += cooked[0];
    for (let i = 0; i < length; i++) {
      expressions[i].accept(this);
      this.text += cooked[i + 1];
    }
    this.text += '`';
  }

descendant: { cooked, expressions } = expr and this is a VariableDeclaration with undefined type!!!
AST.TemplateExpression is a class.

Error: message:"Cannot read property 'flags' of undefined"

image

@HamedFathi could you post a reproducible example (something I can copy and paste to reproduce) and include the full error message? Thanks.

Was this page helpful?
0 / 5 - 0 ratings