@@ -3992,6 +3992,23 @@ namespace ts {
3992
3992
return true;
3993
3993
}
3994
3994
3995
+ function isTupleTypeDuplicateOf(source: TupleType, target: TupleType): boolean {
3996
+ let sourceTypes = source.elementTypes;
3997
+ let targetTypes = target.elementTypes;
3998
+ if (sourceTypes.length !== targetTypes.length) {
3999
+ return false;
4000
+ }
4001
+ for (var i = 0; i < sourceTypes.length; i++) {
4002
+ if (!isTypeDuplicateOf(sourceTypes[i], targetTypes[i])) {
4003
+ return false;
4004
+ }
4005
+ }
4006
+ return true;
4007
+ }
4008
+
4009
+ // Returns true if the source type is a duplicate of the target type. A source type is a duplicate of
4010
+ // a target type if the the two are identical, with the exception that the source type may have null or
4011
+ // undefined in places where the target type doesn't. This is by design an asymmetric relationship.
3995
4012
function isTypeDuplicateOf(source: Type, target: Type): boolean {
3996
4013
if (source === target) {
3997
4014
return true;
@@ -4005,6 +4022,9 @@ namespace ts {
4005
4022
if (isArrayType(source) && isArrayType(target)) {
4006
4023
return isTypeDuplicateOf((<TypeReference>source).typeArguments[0], (<TypeReference>target).typeArguments[0]);
4007
4024
}
4025
+ if (isTupleType(source) && isTupleType(target)) {
4026
+ return isTupleTypeDuplicateOf(<TupleType>source, <TupleType>target);
4027
+ }
4008
4028
return isTypeIdenticalTo(source, target);
4009
4029
}
4010
4030
@@ -4050,11 +4070,11 @@ namespace ts {
4050
4070
return type1.id - type2.id;
4051
4071
}
4052
4072
4053
- // The noDeduplication flag exists because it isn't always possible to deduplicate the constituent types.
4054
- // The flag is true when creating a union type from a type node and when instantiating a union type. In
4055
- // both of those cases subtype deduplication has to be deferred to properly support recursive union types.
4056
- // For example, a type alias of the form "type Item = string | (() => Item)" cannot be deduplicated during
4057
- // its declaration.
4073
+ // We always deduplicate the constituent type set based on object identity, but we'll also deduplicate
4074
+ // based on the structure of the types unless the noDeduplication flag is true, which is the case when
4075
+ // creating a union type from a type node and when instantiating a union type. In both of those cases,
4076
+ // structural deduplication has to be deferred to properly support recursive union types. For example,
4077
+ // a type of the form "type Item = string | (() => Item)" cannot be deduplicated during its declaration.
4058
4078
function getUnionType(types: Type[], noDeduplication?: boolean): Type {
4059
4079
if (types.length === 0) {
4060
4080
return emptyObjectType;
@@ -4133,7 +4153,7 @@ namespace ts {
4133
4153
return links.resolvedType;
4134
4154
}
4135
4155
4136
- // We do not perform supertype reduction on intersection types. Intersection types are created only by the &
4156
+ // We do not perform structural deduplication on intersection types. Intersection types are created only by the &
4137
4157
// type operator and we can't reduce those because we want to support recursive intersection types. For example,
4138
4158
// a type alias of the form "type List<T> = T & { next: List<T> }" cannot be reduced during its declaration.
4139
4159
// Also, unlike union types, the order of the constituent types is preserved in order that overload resolution
0 commit comments