@@ -6519,6 +6519,23 @@ namespace ts {
6519
6519
6520
6520
function instantiateType(type: Type, mapper: TypeMapper): Type {
6521
6521
if (type && mapper !== identityMapper) {
6522
+ // If we are instantiating a type that has a top-level type alias, obtain the instantiation through
6523
+ // the type alias instead in order to share instantiations for the same type arguments. This can
6524
+ // dramatically reduce the number of structurally identical types we generate. Note that we can only
6525
+ // perform this optimization for top-level type aliases. Consider:
6526
+ //
6527
+ // function f1<T>(x: T) {
6528
+ // type Foo<X> = { x: X, t: T };
6529
+ // let obj: Foo<T> = { x: x };
6530
+ // return obj;
6531
+ // }
6532
+ // function f2<U>(x: U) { return f1(x); }
6533
+ // let z = f2(42);
6534
+ //
6535
+ // Above, the declaration of f2 has an inferred return type that is an instantiation of f1's Foo<X>
6536
+ // equivalent to { x: U, t: U }. When instantiating this return type, we can't go back to Foo<X>'s
6537
+ // cache because all cached instantiations are of the form { x: ???, t: T }, i.e. they have not been
6538
+ // instantiated for T. Instead, we need to further instantiate the { x: U, t: U } form.
6522
6539
if (type.aliasSymbol && isTopLevelTypeAlias(type.aliasSymbol)) {
6523
6540
if (type.aliasTypeArguments) {
6524
6541
return getTypeAliasInstantiation(type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper));
0 commit comments