Skip to content

Commit ef9f6ee

Browse files
committed
Retain errorType when it is used as a marker for the lack of a constraint
1 parent 02bd1a1 commit ef9f6ee

7 files changed

+70
-710
lines changed

src/compiler/checker.ts

+18-16
Original file line numberDiff line numberDiff line change
@@ -6908,7 +6908,7 @@ namespace ts {
69086908
function getConstraintOfIndexedAccess(type: IndexedAccessType) {
69096909
const objectType = getBaseConstraintOfType(type.objectType) || type.objectType;
69106910
const indexType = getBaseConstraintOfType(type.indexType) || type.indexType;
6911-
const constraint = !isGenericObjectType(objectType) && !isGenericIndexType(indexType) ? getIndexedAccessType(objectType, indexType) : undefined;
6911+
const constraint = !isGenericObjectType(objectType) && !isGenericIndexType(indexType) ? getIndexedAccessType(objectType, indexType, /*accessNode*/ undefined, errorType) : undefined;
69126912
return constraint && constraint !== errorType ? constraint : undefined;
69136913
}
69146914

@@ -7059,7 +7059,7 @@ namespace ts {
70597059
if (t.flags & TypeFlags.IndexedAccess) {
70607060
const baseObjectType = getBaseConstraint((<IndexedAccessType>t).objectType);
70617061
const baseIndexType = getBaseConstraint((<IndexedAccessType>t).indexType);
7062-
const baseIndexedAccess = baseObjectType && baseIndexType ? getIndexedAccessType(baseObjectType, baseIndexType) : undefined;
7062+
const baseIndexedAccess = baseObjectType && baseIndexType ? getIndexedAccessType(baseObjectType, baseIndexType, /*accessNode*/ undefined, errorType) : undefined;
70637063
return baseIndexedAccess && baseIndexedAccess !== errorType ? getBaseConstraint(baseIndexedAccess) : undefined;
70647064
}
70657065
if (t.flags & TypeFlags.Conditional) {
@@ -9144,7 +9144,7 @@ namespace ts {
91449144
return false;
91459145
}
91469146

9147-
function getPropertyTypeForIndexType(objectType: Type, indexType: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode | undefined, cacheSymbol: boolean) {
9147+
function getPropertyTypeForIndexType(objectType: Type, indexType: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode | undefined, cacheSymbol: boolean, missingType: Type) {
91489148
const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode : undefined;
91499149
const propName = isTypeUsableAsLateBoundName(indexType) ? getLateBoundNameFromType(indexType) :
91509150
accessExpression && checkThatExpressionIsProperSymbolReference(accessExpression.argumentExpression, indexType, /*reportError*/ false) ?
@@ -9216,7 +9216,7 @@ namespace ts {
92169216
}
92179217
}
92189218
}
9219-
return accessNode ? errorType : unknownType;
9219+
return missingType;
92209220
}
92219221
}
92229222
if (isJSLiteralType(objectType)) {
@@ -9237,7 +9237,7 @@ namespace ts {
92379237
if (isTypeAny(indexType)) {
92389238
return indexType;
92399239
}
9240-
return accessNode ? errorType : unknownType;
9240+
return missingType;
92419241
}
92429242

92439243
function isGenericObjectType(type: Type): boolean {
@@ -9290,7 +9290,7 @@ namespace ts {
92909290
return instantiateType(getTemplateTypeFromMappedType(objectType), templateMapper);
92919291
}
92929292

9293-
function getIndexedAccessType(objectType: Type, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode): Type {
9293+
function getIndexedAccessType(objectType: Type, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode, missingType = accessNode ? errorType : unknownType): Type {
92949294
if (objectType === wildcardType || indexType === wildcardType) {
92959295
return wildcardType;
92969296
}
@@ -9318,18 +9318,15 @@ namespace ts {
93189318
if (indexType.flags & TypeFlags.Union && !(indexType.flags & TypeFlags.Boolean)) {
93199319
const propTypes: Type[] = [];
93209320
for (const t of (<UnionType>indexType).types) {
9321-
const propType = getPropertyTypeForIndexType(apparentObjectType, t, accessNode, /*cacheSymbol*/ false);
9322-
if (propType === unknownType) {
9323-
return unknownType;
9324-
}
9325-
if (propType === errorType) {
9326-
return errorType;
9321+
const propType = getPropertyTypeForIndexType(apparentObjectType, t, accessNode, /*cacheSymbol*/ false, missingType);
9322+
if (propType === missingType) {
9323+
return missingType;
93279324
}
93289325
propTypes.push(propType);
93299326
}
93309327
return getUnionType(propTypes);
93319328
}
9332-
return getPropertyTypeForIndexType(apparentObjectType, indexType, accessNode, /*cacheSymbol*/ true);
9329+
return getPropertyTypeForIndexType(apparentObjectType, indexType, accessNode, /*cacheSymbol*/ true, missingType);
93339330
}
93349331

93359332
function getTypeFromIndexedAccessTypeNode(node: IndexedAccessTypeNode) {
@@ -10476,8 +10473,13 @@ namespace ts {
1047610473
return false;
1047710474
}
1047810475

10476+
function isOrHasGenericConditional(type: Type): boolean {
10477+
return !!(type.flags & TypeFlags.Conditional || (type.flags & TypeFlags.Intersection && some((type as IntersectionType).types, isOrHasGenericConditional)));
10478+
}
10479+
1047910480
function elaborateError(node: Expression | undefined, source: Type, target: Type): boolean {
1048010481
if (!node) return false;
10482+
if (isOrHasGenericConditional(target)) return false;
1048110483
switch (node.kind) {
1048210484
case SyntaxKind.JsxExpression:
1048310485
case SyntaxKind.ParenthesizedExpression:
@@ -10510,9 +10512,9 @@ namespace ts {
1051010512
let reportedError = false;
1051110513
for (let status = iterator.next(); !status.done; status = iterator.next()) {
1051210514
const { errorNode: prop, innerExpression: next, nameType, errorMessage } = status.value;
10513-
const sourcePropType = getIndexedAccessType(source, nameType);
10514-
const targetPropType = getIndexedAccessType(target, nameType);
10515-
if (!isTypeAssignableTo(sourcePropType, targetPropType)) {
10515+
const sourcePropType = getIndexedAccessType(source, nameType, /*accessNode*/ undefined, errorType);
10516+
const targetPropType = getIndexedAccessType(target, nameType, /*accessNode*/ undefined, errorType);
10517+
if (sourcePropType !== errorType && targetPropType !== errorType && !isTypeAssignableTo(sourcePropType, targetPropType)) {
1051610518
const elaborated = next && elaborateError(next, sourcePropType, targetPropType);
1051710519
if (elaborated) {
1051810520
reportedError = true;
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
1-
tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType9_ES5.ts(7,5): error TS2418: Type of computed property's value is 'string', which is not assignable to type 'boolean'.
2-
tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType9_ES5.ts(8,5): error TS2418: Type of computed property's value is 'number', which is not assignable to type 'boolean'.
1+
tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType9_ES5.ts(6,5): error TS2322: Type '{ [x: number]: string | number; }' is not assignable to type 'I'.
2+
Index signatures are incompatible.
3+
Type 'string | number' is not assignable to type 'boolean'.
4+
Type 'string' is not assignable to type 'boolean'.
35

46

5-
==== tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType9_ES5.ts (2 errors) ====
7+
==== tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType9_ES5.ts (1 errors) ====
68
interface I {
79
[s: string]: boolean;
810
[s: number]: boolean;
911
}
1012

1113
var o: I = {
14+
~
15+
!!! error TS2322: Type '{ [x: number]: string | number; }' is not assignable to type 'I'.
16+
!!! error TS2322: Index signatures are incompatible.
17+
!!! error TS2322: Type 'string | number' is not assignable to type 'boolean'.
18+
!!! error TS2322: Type 'string' is not assignable to type 'boolean'.
1219
[+"foo"]: "",
13-
~~~~~~~~
14-
!!! error TS2418: Type of computed property's value is 'string', which is not assignable to type 'boolean'.
15-
!!! related TS6501 tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType9_ES5.ts:2:5: The expected type comes from this index signature.
1620
[+"bar"]: 0
17-
~~~~~~~~
18-
!!! error TS2418: Type of computed property's value is 'number', which is not assignable to type 'boolean'.
19-
!!! related TS6501 tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType9_ES5.ts:2:5: The expected type comes from this index signature.
2021
}
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
1-
tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType9_ES6.ts(7,5): error TS2418: Type of computed property's value is 'string', which is not assignable to type 'boolean'.
2-
tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType9_ES6.ts(8,5): error TS2418: Type of computed property's value is 'number', which is not assignable to type 'boolean'.
1+
tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType9_ES6.ts(6,5): error TS2322: Type '{ [x: number]: string | number; }' is not assignable to type 'I'.
2+
Index signatures are incompatible.
3+
Type 'string | number' is not assignable to type 'boolean'.
4+
Type 'string' is not assignable to type 'boolean'.
35

46

5-
==== tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType9_ES6.ts (2 errors) ====
7+
==== tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType9_ES6.ts (1 errors) ====
68
interface I {
79
[s: string]: boolean;
810
[s: number]: boolean;
911
}
1012

1113
var o: I = {
14+
~
15+
!!! error TS2322: Type '{ [x: number]: string | number; }' is not assignable to type 'I'.
16+
!!! error TS2322: Index signatures are incompatible.
17+
!!! error TS2322: Type 'string | number' is not assignable to type 'boolean'.
18+
!!! error TS2322: Type 'string' is not assignable to type 'boolean'.
1219
[+"foo"]: "",
13-
~~~~~~~~
14-
!!! error TS2418: Type of computed property's value is 'string', which is not assignable to type 'boolean'.
15-
!!! related TS6501 tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType9_ES6.ts:2:5: The expected type comes from this index signature.
1620
[+"bar"]: 0
17-
~~~~~~~~
18-
!!! error TS2418: Type of computed property's value is 'number', which is not assignable to type 'boolean'.
19-
!!! related TS6501 tests/cases/conformance/es6/computedProperties/computedPropertyNamesContextualType9_ES6.ts:2:5: The expected type comes from this index signature.
2021
}

0 commit comments

Comments
 (0)