Skip to content

Commit d34557a

Browse files
committed
Deduplication of tuple types in unions
1 parent c42b8f7 commit d34557a

File tree

1 file changed

+26
-6
lines changed

1 file changed

+26
-6
lines changed

src/compiler/checker.ts

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3992,6 +3992,23 @@ namespace ts {
39923992
return true;
39933993
}
39943994

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.
39954012
function isTypeDuplicateOf(source: Type, target: Type): boolean {
39964013
if (source === target) {
39974014
return true;
@@ -4005,6 +4022,9 @@ namespace ts {
40054022
if (isArrayType(source) && isArrayType(target)) {
40064023
return isTypeDuplicateOf((<TypeReference>source).typeArguments[0], (<TypeReference>target).typeArguments[0]);
40074024
}
4025+
if (isTupleType(source) && isTupleType(target)) {
4026+
return isTupleTypeDuplicateOf(<TupleType>source, <TupleType>target);
4027+
}
40084028
return isTypeIdenticalTo(source, target);
40094029
}
40104030

@@ -4050,11 +4070,11 @@ namespace ts {
40504070
return type1.id - type2.id;
40514071
}
40524072

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.
40584078
function getUnionType(types: Type[], noDeduplication?: boolean): Type {
40594079
if (types.length === 0) {
40604080
return emptyObjectType;
@@ -4133,7 +4153,7 @@ namespace ts {
41334153
return links.resolvedType;
41344154
}
41354155

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 &
41374157
// type operator and we can't reduce those because we want to support recursive intersection types. For example,
41384158
// a type alias of the form "type List<T> = T & { next: List<T> }" cannot be reduced during its declaration.
41394159
// Also, unlike union types, the order of the constituent types is preserved in order that overload resolution

0 commit comments

Comments
 (0)