Correct tuple relations in --strictOptionalProperties mode (#44568)

* Fix relations for optional elements in tuples with --strictOptionalProperties

* Accept new baselines

* Add regression test

* Address CR feedback
This commit is contained in:
Anders Hejlsberg
2021-06-13 12:53:13 -07:00
committed by GitHub
parent 6a1623d413
commit 5540364c12
12 changed files with 103 additions and 31 deletions

View File

@@ -15095,11 +15095,11 @@ namespace ts {
}
function isTypicalNondistributiveConditional(root: ConditionalRoot) {
return !root.isDistributive
&& root.node.checkType.kind === SyntaxKind.TupleType
&& length((root.node.checkType as TupleTypeNode).elements) === 1
&& root.node.extendsType.kind === SyntaxKind.TupleType
&& length((root.node.extendsType as TupleTypeNode).elements) === 1;
return !root.isDistributive && isSingletonTupleType(root.node.checkType) && isSingletonTupleType(root.node.extendsType);
}
function isSingletonTupleType(node: TypeNode) {
return isTupleTypeNode(node) && length(node.elements) === 1 && !isOptionalTypeNode(node.elements[0]) && !isRestTypeNode(node.elements[0]);
}
/**
@@ -18711,7 +18711,7 @@ namespace ts {
return Ternary.False;
}
if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (source as TypeReference).target === (target as TypeReference).target &&
!(getObjectFlags(source) & ObjectFlags.MarkerType || getObjectFlags(target) & ObjectFlags.MarkerType)) {
!isTupleType(source) && !(getObjectFlags(source) & ObjectFlags.MarkerType || getObjectFlags(target) & ObjectFlags.MarkerType)) {
// We have type references to the same generic type, and the type references are not marker
// type references (which are intended by be compared structurally). Obtain the variance
// information for the type parameters and relate the type arguments accordingly.
@@ -19182,7 +19182,7 @@ namespace ts {
removeMissingType(targetType, !!(targetFlags & ElementFlags.Optional));
const related = isRelatedTo(sourceType, targetCheckType, reportErrors, /*headMessage*/ undefined, intersectionState);
if (!related) {
if (reportErrors) {
if (reportErrors && (targetArity > 1 || sourceArity > 1)) {
if (i < startCount || i >= targetArity - endCount || sourceArity - startCount - endCount === 1) {
reportIncompatibleError(Diagnostics.Type_at_position_0_in_source_is_not_compatible_with_type_at_position_1_in_target, sourceIndex, i);
}

View File

@@ -21,7 +21,8 @@ tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(28,5): error
Type '2' is not assignable to type '1'.
tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(29,5): error TS2322: Type '{ 0: string; 1: number; length: 2; }' is not assignable to type '[string]'.
tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(30,5): error TS2322: Type '[string, number]' is not assignable to type '[number, string]'.
Type 'string' is not assignable to type 'number'.
Type at position 0 in source is not compatible with type at position 0 in target.
Type 'string' is not assignable to type 'number'.
tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(31,5): error TS2322: Type 'StrNum' is not assignable to type '[number, string]'.
Types of property '0' are incompatible.
Type 'string' is not assignable to type 'number'.
@@ -97,7 +98,8 @@ tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(32,5): error
var n1: [number, string] = x;
~~
!!! error TS2322: Type '[string, number]' is not assignable to type '[number, string]'.
!!! error TS2322: Type 'string' is not assignable to type 'number'.
!!! error TS2322: Type at position 0 in source is not compatible with type at position 0 in target.
!!! error TS2322: Type 'string' is not assignable to type 'number'.
var n2: [number, string] = y;
~~
!!! error TS2322: Type 'StrNum' is not assignable to type '[number, string]'.

View File

@@ -7,9 +7,11 @@ tests/cases/conformance/types/tuple/castingTuple.ts(18,21): error TS2352: Conver
Source has 2 element(s) but target requires 3.
tests/cases/conformance/types/tuple/castingTuple.ts(20,33): error TS2493: Tuple type '[C, D, A]' of length '3' has no element at index '5'.
tests/cases/conformance/types/tuple/castingTuple.ts(30,10): error TS2352: Conversion of type '[number, string]' to type '[number, number]' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
Type 'string' is not comparable to type 'number'.
Type at position 1 in source is not compatible with type at position 1 in target.
Type 'string' is not comparable to type 'number'.
tests/cases/conformance/types/tuple/castingTuple.ts(31,10): error TS2352: Conversion of type '[C, D]' to type '[A, I]' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
Property 'a' is missing in type 'C' but required in type 'A'.
Type at position 0 in source is not compatible with type at position 0 in target.
Property 'a' is missing in type 'C' but required in type 'A'.
tests/cases/conformance/types/tuple/castingTuple.ts(32,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'array1' must be of type '{}[]', but here has type 'number[]'.
tests/cases/conformance/types/tuple/castingTuple.ts(33,1): error TS2304: Cannot find name 't4'.
@@ -60,11 +62,13 @@ tests/cases/conformance/types/tuple/castingTuple.ts(33,1): error TS2304: Cannot
var t3 = <[number, number]>numStrTuple;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2352: Conversion of type '[number, string]' to type '[number, number]' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
!!! error TS2352: Type 'string' is not comparable to type 'number'.
!!! error TS2352: Type at position 1 in source is not compatible with type at position 1 in target.
!!! error TS2352: Type 'string' is not comparable to type 'number'.
var t9 = <[A, I]>classCDTuple;
~~~~~~~~~~~~~~~~~~~~
!!! error TS2352: Conversion of type '[C, D]' to type '[A, I]' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
!!! error TS2352: Property 'a' is missing in type 'C' but required in type 'A'.
!!! error TS2352: Type at position 0 in source is not compatible with type at position 0 in target.
!!! error TS2352: Property 'a' is missing in type 'C' but required in type 'A'.
!!! related TS2728 tests/cases/conformance/types/tuple/castingTuple.ts:2:11: 'a' is declared here.
var array1 = <number[]>numStrTuple;
~~~~~~

View File

@@ -12,8 +12,9 @@ tests/cases/conformance/types/tuple/contextualTypeWithTuple.ts(23,1): error TS23
tests/cases/conformance/types/tuple/contextualTypeWithTuple.ts(24,1): error TS2322: Type '[C, string | number]' is not assignable to type '[C, string | number, D]'.
Source has 2 element(s) but target requires 3.
tests/cases/conformance/types/tuple/contextualTypeWithTuple.ts(25,1): error TS2322: Type '[number, string | number]' is not assignable to type '[number, string]'.
Type 'string | number' is not assignable to type 'string'.
Type 'number' is not assignable to type 'string'.
Type at position 1 in source is not compatible with type at position 1 in target.
Type 'string | number' is not assignable to type 'string'.
Type 'number' is not assignable to type 'string'.
==== tests/cases/conformance/types/tuple/contextualTypeWithTuple.ts (8 errors) ====
@@ -65,5 +66,6 @@ tests/cases/conformance/types/tuple/contextualTypeWithTuple.ts(25,1): error TS23
numStrTuple = unionTuple3;
~~~~~~~~~~~
!!! error TS2322: Type '[number, string | number]' is not assignable to type '[number, string]'.
!!! error TS2322: Type 'string | number' is not assignable to type 'string'.
!!! error TS2322: Type 'number' is not assignable to type 'string'.
!!! error TS2322: Type at position 1 in source is not compatible with type at position 1 in target.
!!! error TS2322: Type 'string | number' is not assignable to type 'string'.
!!! error TS2322: Type 'number' is not assignable to type 'string'.

View File

@@ -1,5 +1,6 @@
tests/cases/conformance/es6/destructuring/iterableArrayPattern29.ts(2,21): error TS2345: Argument of type '[string, boolean]' is not assignable to parameter of type '[string, number]'.
Type 'boolean' is not assignable to type 'number'.
Type at position 1 in source is not compatible with type at position 1 in target.
Type 'boolean' is not assignable to type 'number'.
==== tests/cases/conformance/es6/destructuring/iterableArrayPattern29.ts (1 errors) ====
@@ -7,4 +8,5 @@ tests/cases/conformance/es6/destructuring/iterableArrayPattern29.ts(2,21): error
takeFirstTwoEntries(...new Map([["", true], ["hello", true]]));
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2345: Argument of type '[string, boolean]' is not assignable to parameter of type '[string, number]'.
!!! error TS2345: Type 'boolean' is not assignable to type 'number'.
!!! error TS2345: Type at position 1 in source is not compatible with type at position 1 in target.
!!! error TS2345: Type 'boolean' is not assignable to type 'number'.

View File

@@ -11,9 +11,11 @@ tests/cases/conformance/types/tuple/restTupleElements1.ts(29,18): error TS2344:
tests/cases/conformance/types/tuple/restTupleElements1.ts(30,18): error TS2344: Type '[number, ...number[]]' does not satisfy the constraint '[number]'.
Target allows only 1 element(s) but source may have more.
tests/cases/conformance/types/tuple/restTupleElements1.ts(32,31): error TS2344: Type '[number, ...string[]]' does not satisfy the constraint '[number, ...number[]]'.
Type 'string' is not assignable to type 'number'.
Type at position 1 in source is not compatible with type at position 1 in target.
Type 'string' is not assignable to type 'number'.
tests/cases/conformance/types/tuple/restTupleElements1.ts(33,31): error TS2344: Type '[string, ...number[]]' does not satisfy the constraint '[number, ...number[]]'.
Type 'string' is not assignable to type 'number'.
Type at position 0 in source is not compatible with type at position 0 in target.
Type 'string' is not assignable to type 'number'.
tests/cases/conformance/types/tuple/restTupleElements1.ts(34,31): error TS2344: Type '[number, number, string]' does not satisfy the constraint '[number, ...number[]]'.
Type at positions 1 through 2 in source is not compatible with type at position 1 in target.
Type 'string | number' is not assignable to type 'number'.
@@ -81,11 +83,13 @@ tests/cases/conformance/types/tuple/restTupleElements1.ts(59,4): error TS2345: A
assign<[number, ...number[]], [number, ...string[]]>(); // Error
~~~~~~~~~~~~~~~~~~~~~
!!! error TS2344: Type '[number, ...string[]]' does not satisfy the constraint '[number, ...number[]]'.
!!! error TS2344: Type 'string' is not assignable to type 'number'.
!!! error TS2344: Type at position 1 in source is not compatible with type at position 1 in target.
!!! error TS2344: Type 'string' is not assignable to type 'number'.
assign<[number, ...number[]], [string, ...number[]]>(); // Error
~~~~~~~~~~~~~~~~~~~~~
!!! error TS2344: Type '[string, ...number[]]' does not satisfy the constraint '[number, ...number[]]'.
!!! error TS2344: Type 'string' is not assignable to type 'number'.
!!! error TS2344: Type at position 0 in source is not compatible with type at position 0 in target.
!!! error TS2344: Type 'string' is not assignable to type 'number'.
assign<[number, ...number[]], [number, number, string]>(); // Error
~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2344: Type '[number, number, string]' does not satisfy the constraint '[number, ...number[]]'.

View File

@@ -0,0 +1,19 @@
//// [strictOptionalProperties2.ts]
// Repro from #44567
type T1 = { 0?: string | undefined } extends { 0?: string } ? true : false; // false
type T2 = [(string | undefined)?] extends [string?] ? true : false; // false
//// [strictOptionalProperties2.js]
"use strict";
// Repro from #44567
//// [strictOptionalProperties2.d.ts]
declare type T1 = {
0?: string | undefined;
} extends {
0?: string;
} ? true : false;
declare type T2 = [(string | undefined)?] extends [string?] ? true : false;

View File

@@ -0,0 +1,11 @@
=== tests/cases/compiler/strictOptionalProperties2.ts ===
// Repro from #44567
type T1 = { 0?: string | undefined } extends { 0?: string } ? true : false; // false
>T1 : Symbol(T1, Decl(strictOptionalProperties2.ts, 0, 0))
>0 : Symbol(0, Decl(strictOptionalProperties2.ts, 2, 11))
>0 : Symbol(0, Decl(strictOptionalProperties2.ts, 2, 46))
type T2 = [(string | undefined)?] extends [string?] ? true : false; // false
>T2 : Symbol(T2, Decl(strictOptionalProperties2.ts, 2, 75))

View File

@@ -0,0 +1,15 @@
=== tests/cases/compiler/strictOptionalProperties2.ts ===
// Repro from #44567
type T1 = { 0?: string | undefined } extends { 0?: string } ? true : false; // false
>T1 : false
>0 : string | undefined
>0 : string | undefined
>true : true
>false : false
type T2 = [(string | undefined)?] extends [string?] ? true : false; // false
>T2 : false
>true : true
>false : false

View File

@@ -18,9 +18,11 @@ tests/cases/compiler/tupleTypes.ts(49,1): error TS2322: Type '[number, {}]' is n
Type 'number | {}' is not assignable to type 'number'.
Type '{}' is not assignable to type 'number'.
tests/cases/compiler/tupleTypes.ts(50,1): error TS2322: Type '[number, number]' is not assignable to type '[number, string]'.
Type 'number' is not assignable to type 'string'.
Type at position 1 in source is not compatible with type at position 1 in target.
Type 'number' is not assignable to type 'string'.
tests/cases/compiler/tupleTypes.ts(51,1): error TS2322: Type '[number, {}]' is not assignable to type '[number, string]'.
Type '{}' is not assignable to type 'string'.
Type at position 1 in source is not compatible with type at position 1 in target.
Type '{}' is not assignable to type 'string'.
==== tests/cases/compiler/tupleTypes.ts (14 errors) ====
@@ -109,11 +111,13 @@ tests/cases/compiler/tupleTypes.ts(51,1): error TS2322: Type '[number, {}]' is n
a1 = a2; // Error
~~
!!! error TS2322: Type '[number, number]' is not assignable to type '[number, string]'.
!!! error TS2322: Type 'number' is not assignable to type 'string'.
!!! error TS2322: Type at position 1 in source is not compatible with type at position 1 in target.
!!! error TS2322: Type 'number' is not assignable to type 'string'.
a1 = a3; // Error
~~
!!! error TS2322: Type '[number, {}]' is not assignable to type '[number, string]'.
!!! error TS2322: Type '{}' is not assignable to type 'string'.
!!! error TS2322: Type at position 1 in source is not compatible with type at position 1 in target.
!!! error TS2322: Type '{}' is not assignable to type 'string'.
a3 = a1;
a3 = a2;

View File

@@ -9,8 +9,9 @@ tests/cases/conformance/types/tuple/variadicTuples1.ts(149,5): error TS2322: Typ
tests/cases/conformance/types/tuple/variadicTuples1.ts(151,5): error TS2322: Type '[string, ...unknown[]]' is not assignable to type '[string, ...U]'.
Target requires 2 element(s) but source may have fewer.
tests/cases/conformance/types/tuple/variadicTuples1.ts(152,5): error TS2322: Type '[string, ...T]' is not assignable to type '[string, ...U]'.
Type 'T' is not assignable to type 'U'.
'T' is assignable to the constraint of type 'U', but 'U' could be instantiated with a different subtype of constraint 'string[]'.
Type at position 1 in source is not compatible with type at position 1 in target.
Type 'T' is not assignable to type 'U'.
'T' is assignable to the constraint of type 'U', but 'U' could be instantiated with a different subtype of constraint 'string[]'.
tests/cases/conformance/types/tuple/variadicTuples1.ts(160,5): error TS2322: Type 'readonly [...T]' is not assignable to type 'T'.
'T' could be instantiated with an arbitrary type which could be unrelated to 'readonly [...T]'.
tests/cases/conformance/types/tuple/variadicTuples1.ts(162,5): error TS4104: The type 'readonly [...T]' is 'readonly' and cannot be assigned to the mutable type '[...T]'.
@@ -212,8 +213,9 @@ tests/cases/conformance/types/tuple/variadicTuples1.ts(397,7): error TS2322: Typ
z = y; // Error
~
!!! error TS2322: Type '[string, ...T]' is not assignable to type '[string, ...U]'.
!!! error TS2322: Type 'T' is not assignable to type 'U'.
!!! error TS2322: 'T' is assignable to the constraint of type 'U', but 'U' could be instantiated with a different subtype of constraint 'string[]'.
!!! error TS2322: Type at position 1 in source is not compatible with type at position 1 in target.
!!! error TS2322: Type 'T' is not assignable to type 'U'.
!!! error TS2322: 'T' is assignable to the constraint of type 'U', but 'U' could be instantiated with a different subtype of constraint 'string[]'.
}
// For a generic type T, [...T] is assignable to T, T is assignable to readonly [...T], and T is assignable

View File

@@ -0,0 +1,7 @@
// @strict: true
// @declaration: true
// Repro from #44567
type T1 = { 0?: string | undefined } extends { 0?: string } ? true : false; // false
type T2 = [(string | undefined)?] extends [string?] ? true : false; // false