@@ -6519,6 +6519,23 @@ namespace ts {
65196519
65206520 function instantiateType(type: Type, mapper: TypeMapper): Type {
65216521 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.
65226539 if (type.aliasSymbol && isTopLevelTypeAlias(type.aliasSymbol)) {
65236540 if (type.aliasTypeArguments) {
65246541 return getTypeAliasInstantiation(type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper));
0 commit comments