The ts2famix
npm package provides the ability to analyze TypeScript projects by breaking down their components and generating a model with detailed information. However, both ts2famix and its corresponding metamodel initially had limitations in accurately recognizing parametric elements and concretization relationships. During my Summer 2024 internship, I focused on improving the recognition of these elements and their representation, enhancing their accuracy in both the ts2famix-generated JSON file and our metamodel.
Assumptions
In this post, we assume familiarity with TypeScript’s generic types and their usage. We’ll explore how generics and concretization relationships are represented in both our metamodel and ts2famix.
Understanding Genericity and Concretization
Genericity refers to the ability to define classes, methods, or types that can operate on different data types. In TypeScript, generics allow developers to write reusable code that can handle various data types while maintaining type safety.
// Parametric Class
class ClassA< T > {
private value: T;
constructor(value: T) {
this.value = value;
} }
For example, a generic class like ClassA
can be defined with a type parameter T
, making it flexible to work with different types, but it cannot be used without specifying the type for T
.
Concretization occurs when these generic types are assigned specific values or types, turning abstract type parameters into concrete instances.
class ClassB extends ClassA< string > {
// In Famix, ClassA is modeled as a ParametricClass with type string
// ClassB and string are modeled as Class and PrimitiveType, respectively
}
In the case of ClassA
, concretization would involve setting T
to a specific type like string
.
< T > { /* ... */ }
ClassA
extends ClassA< string > { /* ... */ }
ClassB
// Modeling the relations in Famix:
// ClassA< T > ==Concretization==> ClassA< string >
// T ==ParameterConcretization==> string
In this example, we have two classes: ClassA< T >
, a generic class with the parameter T
, and ClassA< string >
, a concrete class where T
is specified as string
. This illustrates a concretization relationship between ClassA< T >
and ClassA< string >
, as well as a parameter concretization relationship between the generic parameter T
and the concrete parameter string
.
This example is explained in detail (with an example in Java) throughout this blog post.
Implementation in the FamixTypeScript Metamodel
Now that we’ve established a theoretical understanding of generics and concretization, we can see how these concepts were implemented in our metamodel.
Our metamodel includes 8 new classes:
- Five representing the core generic structures:
ParametricClass
,ParametricInterface
,ParametricFunction
,ParametricMethod
, andParametricArrowFunction
. - A
ParameterType
, which refers to the parameters of a parametric element. - Two classes,
Concretisation
andParameterConcretisation
, defining relationships between parametric elements and between parameter types, respectively.
The use of traits has been key in organizing parametric elements and concretizations, allowing us to handle them in a structured, modular way.
We have 5 new traits in our meta-model:
TParametricEntity
is a general type used by all parametric entities, includingParametricClass
,ParametricInterface
,ParametricFunction
,ParametricMethod
, andParametricArrowFunction
.TConcreteParameterType
represents concrete parameters.TGenericParameterType
represents generic parameters.
TConcretisation
establishes a link between twoTParametricEntity
instances. ATParametricEntity
can have one or more concretizations with otherTParametricEntity
objects. EachTParametricEntity
that is a concretization of another holds a reference to its generic entity.TParameterConcretisation
works similarly toTConcretisation
, but instead of linking twoTParametricEntity
instances, it connects aTConcreteParameterType
with aTGenericParameterType
. ATGenericParameterType
can have multiple concretizations, and aTConcreteParameterType
contains references to its generics.
These relations are explained in detail throughout this blog post.
Unified Approach in the Metamodel and ts2famix
Both our metamodel and the ts2famix
npm package share a consistent approach to representing generics and concretization relationships. In our metamodel, parametric elements and their concretizations are modeled clearly to reflect the relationships between abstract types and their concrete instances. These representations are aligned with how ts2famix
handles generics in TypeScript projects, ensuring that improvements in the recognition of parametric elements are mirrored in both the model and the code analysis process.
Conclusion
In this post, we’ve explored how generics and concretization relationships are modeled both in our metamodel and the ts2famix
npm package. By ensuring a consistent approach across both systems, we’ve enhanced the accuracy and usability of these parametric elements in TypeScript project analysis.