diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7f05c9b40df23..e0ab7922564ae 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -29665,15 +29665,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isConstraintPosition(type: Type, node: Node) { const parent = node.parent; - // In an element access obj[x], we consider obj to be in a constraint position, except when obj is of - // a generic type without a nullable constraint and x is a generic type. This is because when both obj - // and x are of generic types T and K, we want the resulting type to be T[K]. + // In an element access obj[key], we consider obj to be in a constraint position, except when + // obj and key both have generic types. When obj and key are of generic types T and K, we want + // the resulting type to be T[K]. return parent.kind === SyntaxKind.PropertyAccessExpression || parent.kind === SyntaxKind.QualifiedName || parent.kind === SyntaxKind.CallExpression && (parent as CallExpression).expression === node || parent.kind === SyntaxKind.NewExpression && (parent as NewExpression).expression === node || parent.kind === SyntaxKind.ElementAccessExpression && (parent as ElementAccessExpression).expression === node && - !(someType(type, isGenericTypeWithoutNullableConstraint) && isGenericIndexType(getTypeOfExpression((parent as ElementAccessExpression).argumentExpression))); + !(isGenericObjectType(type) && isGenericIndexType(getTypeOfExpression((parent as ElementAccessExpression).argumentExpression))); } function isGenericTypeWithUnionConstraint(type: Type): boolean { @@ -29682,12 +29682,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { !!(type.flags & TypeFlags.Instantiable && getBaseConstraintOrType(type).flags & (TypeFlags.Nullable | TypeFlags.Union)); } - function isGenericTypeWithoutNullableConstraint(type: Type): boolean { - return type.flags & TypeFlags.Intersection ? - some((type as IntersectionType).types, isGenericTypeWithoutNullableConstraint) : - !!(type.flags & TypeFlags.Instantiable && !maybeTypeOfKind(getBaseConstraintOrType(type), TypeFlags.Nullable)); - } - function hasContextualTypeWithNoGenericTypes(node: Node, checkMode: CheckMode | undefined) { // Computing the contextual type for a child of a JSX element involves resolving the type of the // element's tag name, so we exclude that here to avoid circularities. @@ -34589,14 +34583,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkIndexedAccess(node: ElementAccessExpression, checkMode: CheckMode | undefined): Type { - return node.flags & NodeFlags.OptionalChain ? checkElementAccessChain(node as ElementAccessChain, checkMode) : - checkElementAccessExpression(node, checkNonNullExpression(node.expression), checkMode); - } - - function checkElementAccessChain(node: ElementAccessChain, checkMode: CheckMode | undefined) { + const isOptional = node.flags & NodeFlags.OptionalChain; const exprType = checkExpression(node.expression); - const nonOptionalType = getOptionalExpressionType(exprType, node.expression); - return propagateOptionalTypeMarker(checkElementAccessExpression(node, checkNonNullType(nonOptionalType, node.expression), checkMode), node, nonOptionalType !== exprType); + const nonOptionalType = isOptional ? getOptionalExpressionType(exprType, node.expression) : exprType; + const nonNullType = maybeTypeOfKind(nonOptionalType, TypeFlags.Unknown | TypeFlags.Nullable) ? checkNonNullType(nonOptionalType, node.expression) : nonOptionalType; + const elementType = checkElementAccessExpression(node, nonNullType, checkMode); + return isOptional ? propagateOptionalTypeMarker(elementType, node as ElementAccessChain, nonOptionalType !== exprType) : elementType; } function checkElementAccessExpression(node: ElementAccessExpression, exprType: Type, checkMode: CheckMode | undefined): Type { diff --git a/tests/baselines/reference/controlFlowGenericTypes.errors.txt b/tests/baselines/reference/controlFlowGenericTypes.errors.txt index 27101aaa81cc4..f78e67823d8f7 100644 --- a/tests/baselines/reference/controlFlowGenericTypes.errors.txt +++ b/tests/baselines/reference/controlFlowGenericTypes.errors.txt @@ -5,9 +5,9 @@ controlFlowGenericTypes.ts(81,11): error TS2339: Property 'foo' does not exist o controlFlowGenericTypes.ts(90,44): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value. controlFlowGenericTypes.ts(91,11): error TS2339: Property 'foo' does not exist on type 'MyUnion'. Property 'foo' does not exist on type 'AA'. -controlFlowGenericTypes.ts(156,16): error TS18048: 'obj' is possibly 'undefined'. -controlFlowGenericTypes.ts(167,9): error TS18048: 'iSpec' is possibly 'undefined'. -controlFlowGenericTypes.ts(168,9): error TS18048: 'iSpec' is possibly 'undefined'. +controlFlowGenericTypes.ts(176,16): error TS18049: 'obj' is possibly 'null' or 'undefined'. +controlFlowGenericTypes.ts(182,16): error TS18049: 'obj' is possibly 'null' or 'undefined'. +controlFlowGenericTypes.ts(195,9): error TS2536: Type 'keyof PublicSpec' cannot be used to index type 'InternalSpec'. ==== controlFlowGenericTypes.ts (8 errors) ==== @@ -163,25 +163,54 @@ controlFlowGenericTypes.ts(168,9): error TS18048: 'iSpec' is possibly 'undefined emittingObject.off(eventName as typeof eventName, 0); } - // In an element access obj[x], we consider obj to be in a constraint position, except when obj is of - // a generic type without a nullable constraint and x is a generic type. This is because when both obj - // and x are of generic types T and K, we want the resulting type to be T[K]. + // In an element access obj[key], we consider obj to be in a constraint position, except when + // obj and key both have generic types. When obj and key are of generic types T and K, we want + // the resulting type to be T[K]. function fx1(obj: T, key: K) { const x1 = obj[key]; const x2 = obj && obj[key]; + const x3 = obj?.[key]; } function fx2, K extends keyof T>(obj: T, key: K) { const x1 = obj[key]; const x2 = obj && obj[key]; + const x3 = obj?.[key]; } function fx3 | undefined, K extends keyof T>(obj: T, key: K) { + const x1 = obj[key]; + const x2 = obj && obj[key]; + const x3 = obj?.[key]; + } + + function fx4(obj: T, key: K) { + const x1 = obj[key]; + const x2 = obj && obj[key]; + const x3 = obj?.[key]; + } + + function fx5(obj: T, key: K) { + const x1 = obj[key]; + const x2 = obj && obj[key]; + const x3 = obj?.[key]; + } + + function fx6(obj: T | null | undefined, key: K) { const x1 = obj[key]; // Error ~~~ -!!! error TS18048: 'obj' is possibly 'undefined'. +!!! error TS18049: 'obj' is possibly 'null' or 'undefined'. const x2 = obj && obj[key]; + const x3 = obj?.[key]; + } + + function fx7(obj: { x: T } | null | undefined, key: K) { + const x1 = obj.x[key]; // Error + ~~~ +!!! error TS18049: 'obj' is possibly 'null' or 'undefined'. + const x2 = obj && obj.x[key]; + const x3 = obj?.x[key]; } // Repro from #44166 @@ -191,12 +220,10 @@ controlFlowGenericTypes.ts(168,9): error TS18048: 'iSpec' is possibly 'undefined InternalSpec extends Record | undefined = undefined> { m() { let iSpec = null! as InternalSpec; - iSpec[null! as keyof InternalSpec]; // Error, object possibly undefined - ~~~~~ -!!! error TS18048: 'iSpec' is possibly 'undefined'. - iSpec[null! as keyof PublicSpec]; // Error, object possibly undefined - ~~~~~ -!!! error TS18048: 'iSpec' is possibly 'undefined'. + iSpec[null! as keyof InternalSpec]; + iSpec[null! as keyof PublicSpec]; // Error + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2536: Type 'keyof PublicSpec' cannot be used to index type 'InternalSpec'. if (iSpec === undefined) { return; } diff --git a/tests/baselines/reference/controlFlowGenericTypes.js b/tests/baselines/reference/controlFlowGenericTypes.js index d22dd7421ed0c..4236bf88bf9d7 100644 --- a/tests/baselines/reference/controlFlowGenericTypes.js +++ b/tests/baselines/reference/controlFlowGenericTypes.js @@ -141,23 +141,50 @@ function once>(emittingObject: T, eventName: keyo emittingObject.off(eventName as typeof eventName, 0); } -// In an element access obj[x], we consider obj to be in a constraint position, except when obj is of -// a generic type without a nullable constraint and x is a generic type. This is because when both obj -// and x are of generic types T and K, we want the resulting type to be T[K]. +// In an element access obj[key], we consider obj to be in a constraint position, except when +// obj and key both have generic types. When obj and key are of generic types T and K, we want +// the resulting type to be T[K]. function fx1(obj: T, key: K) { const x1 = obj[key]; const x2 = obj && obj[key]; + const x3 = obj?.[key]; } function fx2, K extends keyof T>(obj: T, key: K) { const x1 = obj[key]; const x2 = obj && obj[key]; + const x3 = obj?.[key]; } function fx3 | undefined, K extends keyof T>(obj: T, key: K) { + const x1 = obj[key]; + const x2 = obj && obj[key]; + const x3 = obj?.[key]; +} + +function fx4(obj: T, key: K) { + const x1 = obj[key]; + const x2 = obj && obj[key]; + const x3 = obj?.[key]; +} + +function fx5(obj: T, key: K) { + const x1 = obj[key]; + const x2 = obj && obj[key]; + const x3 = obj?.[key]; +} + +function fx6(obj: T | null | undefined, key: K) { const x1 = obj[key]; // Error const x2 = obj && obj[key]; + const x3 = obj?.[key]; +} + +function fx7(obj: { x: T } | null | undefined, key: K) { + const x1 = obj.x[key]; // Error + const x2 = obj && obj.x[key]; + const x3 = obj?.x[key]; } // Repro from #44166 @@ -167,8 +194,8 @@ class TableBaseEnum< InternalSpec extends Record | undefined = undefined> { m() { let iSpec = null! as InternalSpec; - iSpec[null! as keyof InternalSpec]; // Error, object possibly undefined - iSpec[null! as keyof PublicSpec]; // Error, object possibly undefined + iSpec[null! as keyof InternalSpec]; + iSpec[null! as keyof PublicSpec]; // Error if (iSpec === undefined) { return; } @@ -327,20 +354,43 @@ function once(emittingObject, eventName) { emittingObject.off(eventName, 0); emittingObject.off(eventName, 0); } -// In an element access obj[x], we consider obj to be in a constraint position, except when obj is of -// a generic type without a nullable constraint and x is a generic type. This is because when both obj -// and x are of generic types T and K, we want the resulting type to be T[K]. +// In an element access obj[key], we consider obj to be in a constraint position, except when +// obj and key both have generic types. When obj and key are of generic types T and K, we want +// the resulting type to be T[K]. function fx1(obj, key) { var x1 = obj[key]; var x2 = obj && obj[key]; + var x3 = obj === null || obj === void 0 ? void 0 : obj[key]; } function fx2(obj, key) { var x1 = obj[key]; var x2 = obj && obj[key]; + var x3 = obj === null || obj === void 0 ? void 0 : obj[key]; } function fx3(obj, key) { + var x1 = obj[key]; + var x2 = obj && obj[key]; + var x3 = obj === null || obj === void 0 ? void 0 : obj[key]; +} +function fx4(obj, key) { + var x1 = obj[key]; + var x2 = obj && obj[key]; + var x3 = obj === null || obj === void 0 ? void 0 : obj[key]; +} +function fx5(obj, key) { + var x1 = obj[key]; + var x2 = obj && obj[key]; + var x3 = obj === null || obj === void 0 ? void 0 : obj[key]; +} +function fx6(obj, key) { var x1 = obj[key]; // Error var x2 = obj && obj[key]; + var x3 = obj === null || obj === void 0 ? void 0 : obj[key]; +} +function fx7(obj, key) { + var x1 = obj.x[key]; // Error + var x2 = obj && obj.x[key]; + var x3 = obj === null || obj === void 0 ? void 0 : obj.x[key]; } // Repro from #44166 var TableBaseEnum = /** @class */ (function () { @@ -348,8 +398,8 @@ var TableBaseEnum = /** @class */ (function () { } TableBaseEnum.prototype.m = function () { var iSpec = null; - iSpec[null]; // Error, object possibly undefined - iSpec[null]; // Error, object possibly undefined + iSpec[null]; + iSpec[null]; // Error if (iSpec === undefined) { return; } diff --git a/tests/baselines/reference/controlFlowGenericTypes.symbols b/tests/baselines/reference/controlFlowGenericTypes.symbols index a96581cb4ab9b..136b21aef62f6 100644 --- a/tests/baselines/reference/controlFlowGenericTypes.symbols +++ b/tests/baselines/reference/controlFlowGenericTypes.symbols @@ -407,9 +407,9 @@ function once>(emittingObject: T, eventName: keyo >eventName : Symbol(eventName, Decl(controlFlowGenericTypes.ts, 135, 64)) } -// In an element access obj[x], we consider obj to be in a constraint position, except when obj is of -// a generic type without a nullable constraint and x is a generic type. This is because when both obj -// and x are of generic types T and K, we want the resulting type to be T[K]. +// In an element access obj[key], we consider obj to be in a constraint position, except when +// obj and key both have generic types. When obj and key are of generic types T and K, we want +// the resulting type to be T[K]. function fx1(obj: T, key: K) { >fx1 : Symbol(fx1, Decl(controlFlowGenericTypes.ts, 138, 1)) @@ -430,227 +430,357 @@ function fx1(obj: T, key: K) { >x2 : Symbol(x2, Decl(controlFlowGenericTypes.ts, 146, 9)) >obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 144, 35)) >obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 144, 35)) +>key : Symbol(key, Decl(controlFlowGenericTypes.ts, 144, 42)) + + const x3 = obj?.[key]; +>x3 : Symbol(x3, Decl(controlFlowGenericTypes.ts, 147, 9)) +>obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 144, 35)) >key : Symbol(key, Decl(controlFlowGenericTypes.ts, 144, 42)) } function fx2, K extends keyof T>(obj: T, key: K) { ->fx2 : Symbol(fx2, Decl(controlFlowGenericTypes.ts, 147, 1)) ->T : Symbol(T, Decl(controlFlowGenericTypes.ts, 149, 13)) +>fx2 : Symbol(fx2, Decl(controlFlowGenericTypes.ts, 148, 1)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 150, 13)) >Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) ->T : Symbol(T, Decl(controlFlowGenericTypes.ts, 149, 13)) ->K : Symbol(K, Decl(controlFlowGenericTypes.ts, 149, 47)) ->T : Symbol(T, Decl(controlFlowGenericTypes.ts, 149, 13)) ->obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 149, 67)) ->T : Symbol(T, Decl(controlFlowGenericTypes.ts, 149, 13)) ->key : Symbol(key, Decl(controlFlowGenericTypes.ts, 149, 74)) ->K : Symbol(K, Decl(controlFlowGenericTypes.ts, 149, 47)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 150, 13)) +>K : Symbol(K, Decl(controlFlowGenericTypes.ts, 150, 47)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 150, 13)) +>obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 150, 67)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 150, 13)) +>key : Symbol(key, Decl(controlFlowGenericTypes.ts, 150, 74)) +>K : Symbol(K, Decl(controlFlowGenericTypes.ts, 150, 47)) const x1 = obj[key]; ->x1 : Symbol(x1, Decl(controlFlowGenericTypes.ts, 150, 9)) ->obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 149, 67)) ->key : Symbol(key, Decl(controlFlowGenericTypes.ts, 149, 74)) +>x1 : Symbol(x1, Decl(controlFlowGenericTypes.ts, 151, 9)) +>obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 150, 67)) +>key : Symbol(key, Decl(controlFlowGenericTypes.ts, 150, 74)) const x2 = obj && obj[key]; ->x2 : Symbol(x2, Decl(controlFlowGenericTypes.ts, 151, 9)) ->obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 149, 67)) ->obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 149, 67)) ->key : Symbol(key, Decl(controlFlowGenericTypes.ts, 149, 74)) +>x2 : Symbol(x2, Decl(controlFlowGenericTypes.ts, 152, 9)) +>obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 150, 67)) +>obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 150, 67)) +>key : Symbol(key, Decl(controlFlowGenericTypes.ts, 150, 74)) + + const x3 = obj?.[key]; +>x3 : Symbol(x3, Decl(controlFlowGenericTypes.ts, 153, 9)) +>obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 150, 67)) +>key : Symbol(key, Decl(controlFlowGenericTypes.ts, 150, 74)) } function fx3 | undefined, K extends keyof T>(obj: T, key: K) { ->fx3 : Symbol(fx3, Decl(controlFlowGenericTypes.ts, 152, 1)) ->T : Symbol(T, Decl(controlFlowGenericTypes.ts, 154, 13)) +>fx3 : Symbol(fx3, Decl(controlFlowGenericTypes.ts, 154, 1)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 156, 13)) >Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) ->T : Symbol(T, Decl(controlFlowGenericTypes.ts, 154, 13)) ->K : Symbol(K, Decl(controlFlowGenericTypes.ts, 154, 59)) ->T : Symbol(T, Decl(controlFlowGenericTypes.ts, 154, 13)) ->obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 154, 79)) ->T : Symbol(T, Decl(controlFlowGenericTypes.ts, 154, 13)) ->key : Symbol(key, Decl(controlFlowGenericTypes.ts, 154, 86)) ->K : Symbol(K, Decl(controlFlowGenericTypes.ts, 154, 59)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 156, 13)) +>K : Symbol(K, Decl(controlFlowGenericTypes.ts, 156, 59)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 156, 13)) +>obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 156, 79)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 156, 13)) +>key : Symbol(key, Decl(controlFlowGenericTypes.ts, 156, 86)) +>K : Symbol(K, Decl(controlFlowGenericTypes.ts, 156, 59)) + + const x1 = obj[key]; +>x1 : Symbol(x1, Decl(controlFlowGenericTypes.ts, 157, 9)) +>obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 156, 79)) +>key : Symbol(key, Decl(controlFlowGenericTypes.ts, 156, 86)) + + const x2 = obj && obj[key]; +>x2 : Symbol(x2, Decl(controlFlowGenericTypes.ts, 158, 9)) +>obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 156, 79)) +>obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 156, 79)) +>key : Symbol(key, Decl(controlFlowGenericTypes.ts, 156, 86)) + + const x3 = obj?.[key]; +>x3 : Symbol(x3, Decl(controlFlowGenericTypes.ts, 159, 9)) +>obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 156, 79)) +>key : Symbol(key, Decl(controlFlowGenericTypes.ts, 156, 86)) +} + +function fx4(obj: T, key: K) { +>fx4 : Symbol(fx4, Decl(controlFlowGenericTypes.ts, 160, 1)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 162, 13)) +>K : Symbol(K, Decl(controlFlowGenericTypes.ts, 162, 31)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 162, 13)) +>obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 162, 51)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 162, 13)) +>key : Symbol(key, Decl(controlFlowGenericTypes.ts, 162, 58)) +>K : Symbol(K, Decl(controlFlowGenericTypes.ts, 162, 31)) + + const x1 = obj[key]; +>x1 : Symbol(x1, Decl(controlFlowGenericTypes.ts, 163, 9)) +>obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 162, 51)) +>key : Symbol(key, Decl(controlFlowGenericTypes.ts, 162, 58)) + + const x2 = obj && obj[key]; +>x2 : Symbol(x2, Decl(controlFlowGenericTypes.ts, 164, 9)) +>obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 162, 51)) +>obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 162, 51)) +>key : Symbol(key, Decl(controlFlowGenericTypes.ts, 162, 58)) + + const x3 = obj?.[key]; +>x3 : Symbol(x3, Decl(controlFlowGenericTypes.ts, 165, 9)) +>obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 162, 51)) +>key : Symbol(key, Decl(controlFlowGenericTypes.ts, 162, 58)) +} + +function fx5(obj: T, key: K) { +>fx5 : Symbol(fx5, Decl(controlFlowGenericTypes.ts, 166, 1)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 168, 13)) +>K : Symbol(K, Decl(controlFlowGenericTypes.ts, 168, 45)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 168, 13)) +>obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 168, 65)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 168, 13)) +>key : Symbol(key, Decl(controlFlowGenericTypes.ts, 168, 72)) +>K : Symbol(K, Decl(controlFlowGenericTypes.ts, 168, 45)) + + const x1 = obj[key]; +>x1 : Symbol(x1, Decl(controlFlowGenericTypes.ts, 169, 9)) +>obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 168, 65)) +>key : Symbol(key, Decl(controlFlowGenericTypes.ts, 168, 72)) + + const x2 = obj && obj[key]; +>x2 : Symbol(x2, Decl(controlFlowGenericTypes.ts, 170, 9)) +>obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 168, 65)) +>obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 168, 65)) +>key : Symbol(key, Decl(controlFlowGenericTypes.ts, 168, 72)) + + const x3 = obj?.[key]; +>x3 : Symbol(x3, Decl(controlFlowGenericTypes.ts, 171, 9)) +>obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 168, 65)) +>key : Symbol(key, Decl(controlFlowGenericTypes.ts, 168, 72)) +} + +function fx6(obj: T | null | undefined, key: K) { +>fx6 : Symbol(fx6, Decl(controlFlowGenericTypes.ts, 172, 1)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 174, 13)) +>K : Symbol(K, Decl(controlFlowGenericTypes.ts, 174, 15)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 174, 13)) +>obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 174, 35)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 174, 13)) +>key : Symbol(key, Decl(controlFlowGenericTypes.ts, 174, 61)) +>K : Symbol(K, Decl(controlFlowGenericTypes.ts, 174, 15)) const x1 = obj[key]; // Error ->x1 : Symbol(x1, Decl(controlFlowGenericTypes.ts, 155, 9)) ->obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 154, 79)) ->key : Symbol(key, Decl(controlFlowGenericTypes.ts, 154, 86)) +>x1 : Symbol(x1, Decl(controlFlowGenericTypes.ts, 175, 9)) +>obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 174, 35)) +>key : Symbol(key, Decl(controlFlowGenericTypes.ts, 174, 61)) const x2 = obj && obj[key]; ->x2 : Symbol(x2, Decl(controlFlowGenericTypes.ts, 156, 9)) ->obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 154, 79)) ->obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 154, 79)) ->key : Symbol(key, Decl(controlFlowGenericTypes.ts, 154, 86)) +>x2 : Symbol(x2, Decl(controlFlowGenericTypes.ts, 176, 9)) +>obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 174, 35)) +>obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 174, 35)) +>key : Symbol(key, Decl(controlFlowGenericTypes.ts, 174, 61)) + + const x3 = obj?.[key]; +>x3 : Symbol(x3, Decl(controlFlowGenericTypes.ts, 177, 9)) +>obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 174, 35)) +>key : Symbol(key, Decl(controlFlowGenericTypes.ts, 174, 61)) +} + +function fx7(obj: { x: T } | null | undefined, key: K) { +>fx7 : Symbol(fx7, Decl(controlFlowGenericTypes.ts, 178, 1)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 180, 13)) +>K : Symbol(K, Decl(controlFlowGenericTypes.ts, 180, 15)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 180, 13)) +>obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 180, 35)) +>x : Symbol(x, Decl(controlFlowGenericTypes.ts, 180, 41)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 180, 13)) +>key : Symbol(key, Decl(controlFlowGenericTypes.ts, 180, 68)) +>K : Symbol(K, Decl(controlFlowGenericTypes.ts, 180, 15)) + + const x1 = obj.x[key]; // Error +>x1 : Symbol(x1, Decl(controlFlowGenericTypes.ts, 181, 9)) +>obj.x : Symbol(x, Decl(controlFlowGenericTypes.ts, 180, 41)) +>obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 180, 35)) +>x : Symbol(x, Decl(controlFlowGenericTypes.ts, 180, 41)) +>key : Symbol(key, Decl(controlFlowGenericTypes.ts, 180, 68)) + + const x2 = obj && obj.x[key]; +>x2 : Symbol(x2, Decl(controlFlowGenericTypes.ts, 182, 9)) +>obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 180, 35)) +>obj.x : Symbol(x, Decl(controlFlowGenericTypes.ts, 180, 41)) +>obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 180, 35)) +>x : Symbol(x, Decl(controlFlowGenericTypes.ts, 180, 41)) +>key : Symbol(key, Decl(controlFlowGenericTypes.ts, 180, 68)) + + const x3 = obj?.x[key]; +>x3 : Symbol(x3, Decl(controlFlowGenericTypes.ts, 183, 9)) +>obj?.x : Symbol(x, Decl(controlFlowGenericTypes.ts, 180, 41)) +>obj : Symbol(obj, Decl(controlFlowGenericTypes.ts, 180, 35)) +>x : Symbol(x, Decl(controlFlowGenericTypes.ts, 180, 41)) +>key : Symbol(key, Decl(controlFlowGenericTypes.ts, 180, 68)) } // Repro from #44166 class TableBaseEnum< ->TableBaseEnum : Symbol(TableBaseEnum, Decl(controlFlowGenericTypes.ts, 157, 1)) +>TableBaseEnum : Symbol(TableBaseEnum, Decl(controlFlowGenericTypes.ts, 184, 1)) PublicSpec extends Record, ->PublicSpec : Symbol(PublicSpec, Decl(controlFlowGenericTypes.ts, 161, 20)) +>PublicSpec : Symbol(PublicSpec, Decl(controlFlowGenericTypes.ts, 188, 20)) >Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) ->InternalSpec : Symbol(InternalSpec, Decl(controlFlowGenericTypes.ts, 162, 55)) +>InternalSpec : Symbol(InternalSpec, Decl(controlFlowGenericTypes.ts, 189, 55)) InternalSpec extends Record | undefined = undefined> { ->InternalSpec : Symbol(InternalSpec, Decl(controlFlowGenericTypes.ts, 162, 55)) +>InternalSpec : Symbol(InternalSpec, Decl(controlFlowGenericTypes.ts, 189, 55)) >Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) ->PublicSpec : Symbol(PublicSpec, Decl(controlFlowGenericTypes.ts, 161, 20)) +>PublicSpec : Symbol(PublicSpec, Decl(controlFlowGenericTypes.ts, 188, 20)) m() { ->m : Symbol(TableBaseEnum.m, Decl(controlFlowGenericTypes.ts, 163, 82)) +>m : Symbol(TableBaseEnum.m, Decl(controlFlowGenericTypes.ts, 190, 82)) let iSpec = null! as InternalSpec; ->iSpec : Symbol(iSpec, Decl(controlFlowGenericTypes.ts, 165, 11)) ->InternalSpec : Symbol(InternalSpec, Decl(controlFlowGenericTypes.ts, 162, 55)) +>iSpec : Symbol(iSpec, Decl(controlFlowGenericTypes.ts, 192, 11)) +>InternalSpec : Symbol(InternalSpec, Decl(controlFlowGenericTypes.ts, 189, 55)) - iSpec[null! as keyof InternalSpec]; // Error, object possibly undefined ->iSpec : Symbol(iSpec, Decl(controlFlowGenericTypes.ts, 165, 11)) ->InternalSpec : Symbol(InternalSpec, Decl(controlFlowGenericTypes.ts, 162, 55)) + iSpec[null! as keyof InternalSpec]; +>iSpec : Symbol(iSpec, Decl(controlFlowGenericTypes.ts, 192, 11)) +>InternalSpec : Symbol(InternalSpec, Decl(controlFlowGenericTypes.ts, 189, 55)) - iSpec[null! as keyof PublicSpec]; // Error, object possibly undefined ->iSpec : Symbol(iSpec, Decl(controlFlowGenericTypes.ts, 165, 11)) ->PublicSpec : Symbol(PublicSpec, Decl(controlFlowGenericTypes.ts, 161, 20)) + iSpec[null! as keyof PublicSpec]; // Error +>iSpec : Symbol(iSpec, Decl(controlFlowGenericTypes.ts, 192, 11)) +>PublicSpec : Symbol(PublicSpec, Decl(controlFlowGenericTypes.ts, 188, 20)) if (iSpec === undefined) { ->iSpec : Symbol(iSpec, Decl(controlFlowGenericTypes.ts, 165, 11)) +>iSpec : Symbol(iSpec, Decl(controlFlowGenericTypes.ts, 192, 11)) >undefined : Symbol(undefined) return; } iSpec[null! as keyof InternalSpec]; ->iSpec : Symbol(iSpec, Decl(controlFlowGenericTypes.ts, 165, 11)) ->InternalSpec : Symbol(InternalSpec, Decl(controlFlowGenericTypes.ts, 162, 55)) +>iSpec : Symbol(iSpec, Decl(controlFlowGenericTypes.ts, 192, 11)) +>InternalSpec : Symbol(InternalSpec, Decl(controlFlowGenericTypes.ts, 189, 55)) iSpec[null! as keyof PublicSpec]; ->iSpec : Symbol(iSpec, Decl(controlFlowGenericTypes.ts, 165, 11)) ->PublicSpec : Symbol(PublicSpec, Decl(controlFlowGenericTypes.ts, 161, 20)) +>iSpec : Symbol(iSpec, Decl(controlFlowGenericTypes.ts, 192, 11)) +>PublicSpec : Symbol(PublicSpec, Decl(controlFlowGenericTypes.ts, 188, 20)) } } // Repros from #45145 function f10(x: T, y: Partial) { ->f10 : Symbol(f10, Decl(controlFlowGenericTypes.ts, 174, 1)) ->T : Symbol(T, Decl(controlFlowGenericTypes.ts, 178, 13)) ->a : Symbol(a, Decl(controlFlowGenericTypes.ts, 178, 24)) ->x : Symbol(x, Decl(controlFlowGenericTypes.ts, 178, 50)) ->T : Symbol(T, Decl(controlFlowGenericTypes.ts, 178, 13)) ->y : Symbol(y, Decl(controlFlowGenericTypes.ts, 178, 55)) +>f10 : Symbol(f10, Decl(controlFlowGenericTypes.ts, 201, 1)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 205, 13)) +>a : Symbol(a, Decl(controlFlowGenericTypes.ts, 205, 24)) +>x : Symbol(x, Decl(controlFlowGenericTypes.ts, 205, 50)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 205, 13)) +>y : Symbol(y, Decl(controlFlowGenericTypes.ts, 205, 55)) >Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --)) ->T : Symbol(T, Decl(controlFlowGenericTypes.ts, 178, 13)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 205, 13)) y = x; ->y : Symbol(y, Decl(controlFlowGenericTypes.ts, 178, 55)) ->x : Symbol(x, Decl(controlFlowGenericTypes.ts, 178, 50)) +>y : Symbol(y, Decl(controlFlowGenericTypes.ts, 205, 55)) +>x : Symbol(x, Decl(controlFlowGenericTypes.ts, 205, 50)) } type SqlInsertSet = T extends undefined ? object : { [P in keyof T]: unknown }; ->SqlInsertSet : Symbol(SqlInsertSet, Decl(controlFlowGenericTypes.ts, 180, 1)) ->T : Symbol(T, Decl(controlFlowGenericTypes.ts, 182, 18)) ->T : Symbol(T, Decl(controlFlowGenericTypes.ts, 182, 18)) ->P : Symbol(P, Decl(controlFlowGenericTypes.ts, 182, 57)) ->T : Symbol(T, Decl(controlFlowGenericTypes.ts, 182, 18)) +>SqlInsertSet : Symbol(SqlInsertSet, Decl(controlFlowGenericTypes.ts, 207, 1)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 209, 18)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 209, 18)) +>P : Symbol(P, Decl(controlFlowGenericTypes.ts, 209, 57)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 209, 18)) class SqlTable { ->SqlTable : Symbol(SqlTable, Decl(controlFlowGenericTypes.ts, 182, 82)) ->T : Symbol(T, Decl(controlFlowGenericTypes.ts, 184, 15)) +>SqlTable : Symbol(SqlTable, Decl(controlFlowGenericTypes.ts, 209, 82)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 211, 15)) protected validateRow(_row: Partial>): void { ->validateRow : Symbol(SqlTable.validateRow, Decl(controlFlowGenericTypes.ts, 184, 19)) ->_row : Symbol(_row, Decl(controlFlowGenericTypes.ts, 185, 26)) +>validateRow : Symbol(SqlTable.validateRow, Decl(controlFlowGenericTypes.ts, 211, 19)) +>_row : Symbol(_row, Decl(controlFlowGenericTypes.ts, 212, 26)) >Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --)) ->SqlInsertSet : Symbol(SqlInsertSet, Decl(controlFlowGenericTypes.ts, 180, 1)) ->T : Symbol(T, Decl(controlFlowGenericTypes.ts, 184, 15)) +>SqlInsertSet : Symbol(SqlInsertSet, Decl(controlFlowGenericTypes.ts, 207, 1)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 211, 15)) } public insertRow(row: SqlInsertSet) { ->insertRow : Symbol(SqlTable.insertRow, Decl(controlFlowGenericTypes.ts, 186, 5)) ->row : Symbol(row, Decl(controlFlowGenericTypes.ts, 187, 21)) ->SqlInsertSet : Symbol(SqlInsertSet, Decl(controlFlowGenericTypes.ts, 180, 1)) ->T : Symbol(T, Decl(controlFlowGenericTypes.ts, 184, 15)) +>insertRow : Symbol(SqlTable.insertRow, Decl(controlFlowGenericTypes.ts, 213, 5)) +>row : Symbol(row, Decl(controlFlowGenericTypes.ts, 214, 21)) +>SqlInsertSet : Symbol(SqlInsertSet, Decl(controlFlowGenericTypes.ts, 207, 1)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 211, 15)) this.validateRow(row); ->this.validateRow : Symbol(SqlTable.validateRow, Decl(controlFlowGenericTypes.ts, 184, 19)) ->this : Symbol(SqlTable, Decl(controlFlowGenericTypes.ts, 182, 82)) ->validateRow : Symbol(SqlTable.validateRow, Decl(controlFlowGenericTypes.ts, 184, 19)) ->row : Symbol(row, Decl(controlFlowGenericTypes.ts, 187, 21)) +>this.validateRow : Symbol(SqlTable.validateRow, Decl(controlFlowGenericTypes.ts, 211, 19)) +>this : Symbol(SqlTable, Decl(controlFlowGenericTypes.ts, 209, 82)) +>validateRow : Symbol(SqlTable.validateRow, Decl(controlFlowGenericTypes.ts, 211, 19)) +>row : Symbol(row, Decl(controlFlowGenericTypes.ts, 214, 21)) } } // Repro from #46495 interface Button { ->Button : Symbol(Button, Decl(controlFlowGenericTypes.ts, 190, 1)) +>Button : Symbol(Button, Decl(controlFlowGenericTypes.ts, 217, 1)) type: "button"; ->type : Symbol(Button.type, Decl(controlFlowGenericTypes.ts, 194, 18)) +>type : Symbol(Button.type, Decl(controlFlowGenericTypes.ts, 221, 18)) text: string; ->text : Symbol(Button.text, Decl(controlFlowGenericTypes.ts, 195, 19)) +>text : Symbol(Button.text, Decl(controlFlowGenericTypes.ts, 222, 19)) } interface Checkbox { ->Checkbox : Symbol(Checkbox, Decl(controlFlowGenericTypes.ts, 197, 1)) +>Checkbox : Symbol(Checkbox, Decl(controlFlowGenericTypes.ts, 224, 1)) type: "checkbox"; ->type : Symbol(Checkbox.type, Decl(controlFlowGenericTypes.ts, 199, 20)) +>type : Symbol(Checkbox.type, Decl(controlFlowGenericTypes.ts, 226, 20)) isChecked: boolean; ->isChecked : Symbol(Checkbox.isChecked, Decl(controlFlowGenericTypes.ts, 200, 21)) +>isChecked : Symbol(Checkbox.isChecked, Decl(controlFlowGenericTypes.ts, 227, 21)) } type Control = Button | Checkbox; ->Control : Symbol(Control, Decl(controlFlowGenericTypes.ts, 202, 1)) ->Button : Symbol(Button, Decl(controlFlowGenericTypes.ts, 190, 1)) ->Checkbox : Symbol(Checkbox, Decl(controlFlowGenericTypes.ts, 197, 1)) +>Control : Symbol(Control, Decl(controlFlowGenericTypes.ts, 229, 1)) +>Button : Symbol(Button, Decl(controlFlowGenericTypes.ts, 217, 1)) +>Checkbox : Symbol(Checkbox, Decl(controlFlowGenericTypes.ts, 224, 1)) function update(control : T | undefined, key: K, value: T[K]): void { ->update : Symbol(update, Decl(controlFlowGenericTypes.ts, 204, 33)) ->T : Symbol(T, Decl(controlFlowGenericTypes.ts, 206, 16)) ->Control : Symbol(Control, Decl(controlFlowGenericTypes.ts, 202, 1)) ->K : Symbol(K, Decl(controlFlowGenericTypes.ts, 206, 34)) ->T : Symbol(T, Decl(controlFlowGenericTypes.ts, 206, 16)) ->control : Symbol(control, Decl(controlFlowGenericTypes.ts, 206, 54)) ->T : Symbol(T, Decl(controlFlowGenericTypes.ts, 206, 16)) ->key : Symbol(key, Decl(controlFlowGenericTypes.ts, 206, 78)) ->K : Symbol(K, Decl(controlFlowGenericTypes.ts, 206, 34)) ->value : Symbol(value, Decl(controlFlowGenericTypes.ts, 206, 86)) ->T : Symbol(T, Decl(controlFlowGenericTypes.ts, 206, 16)) ->K : Symbol(K, Decl(controlFlowGenericTypes.ts, 206, 34)) +>update : Symbol(update, Decl(controlFlowGenericTypes.ts, 231, 33)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 233, 16)) +>Control : Symbol(Control, Decl(controlFlowGenericTypes.ts, 229, 1)) +>K : Symbol(K, Decl(controlFlowGenericTypes.ts, 233, 34)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 233, 16)) +>control : Symbol(control, Decl(controlFlowGenericTypes.ts, 233, 54)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 233, 16)) +>key : Symbol(key, Decl(controlFlowGenericTypes.ts, 233, 78)) +>K : Symbol(K, Decl(controlFlowGenericTypes.ts, 233, 34)) +>value : Symbol(value, Decl(controlFlowGenericTypes.ts, 233, 86)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 233, 16)) +>K : Symbol(K, Decl(controlFlowGenericTypes.ts, 233, 34)) if (control !== undefined) { ->control : Symbol(control, Decl(controlFlowGenericTypes.ts, 206, 54)) +>control : Symbol(control, Decl(controlFlowGenericTypes.ts, 233, 54)) >undefined : Symbol(undefined) control[key] = value; ->control : Symbol(control, Decl(controlFlowGenericTypes.ts, 206, 54)) ->key : Symbol(key, Decl(controlFlowGenericTypes.ts, 206, 78)) ->value : Symbol(value, Decl(controlFlowGenericTypes.ts, 206, 86)) +>control : Symbol(control, Decl(controlFlowGenericTypes.ts, 233, 54)) +>key : Symbol(key, Decl(controlFlowGenericTypes.ts, 233, 78)) +>value : Symbol(value, Decl(controlFlowGenericTypes.ts, 233, 86)) } } // Repro from #50465 type Column = (keyof T extends never ? { id?: number | string } : { id: T }) & { title?: string; } ->Column : Symbol(Column, Decl(controlFlowGenericTypes.ts, 210, 1)) ->T : Symbol(T, Decl(controlFlowGenericTypes.ts, 214, 12)) ->T : Symbol(T, Decl(controlFlowGenericTypes.ts, 214, 12)) ->id : Symbol(id, Decl(controlFlowGenericTypes.ts, 214, 43)) ->id : Symbol(id, Decl(controlFlowGenericTypes.ts, 214, 70)) ->T : Symbol(T, Decl(controlFlowGenericTypes.ts, 214, 12)) ->title : Symbol(title, Decl(controlFlowGenericTypes.ts, 214, 83)) +>Column : Symbol(Column, Decl(controlFlowGenericTypes.ts, 237, 1)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 241, 12)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 241, 12)) +>id : Symbol(id, Decl(controlFlowGenericTypes.ts, 241, 43)) +>id : Symbol(id, Decl(controlFlowGenericTypes.ts, 241, 70)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 241, 12)) +>title : Symbol(title, Decl(controlFlowGenericTypes.ts, 241, 83)) function getColumnProperty(column: Column, key: keyof Column) { ->getColumnProperty : Symbol(getColumnProperty, Decl(controlFlowGenericTypes.ts, 214, 101)) ->T : Symbol(T, Decl(controlFlowGenericTypes.ts, 216, 27)) ->column : Symbol(column, Decl(controlFlowGenericTypes.ts, 216, 30)) ->Column : Symbol(Column, Decl(controlFlowGenericTypes.ts, 210, 1)) ->T : Symbol(T, Decl(controlFlowGenericTypes.ts, 216, 27)) ->key : Symbol(key, Decl(controlFlowGenericTypes.ts, 216, 48)) ->Column : Symbol(Column, Decl(controlFlowGenericTypes.ts, 210, 1)) ->T : Symbol(T, Decl(controlFlowGenericTypes.ts, 216, 27)) +>getColumnProperty : Symbol(getColumnProperty, Decl(controlFlowGenericTypes.ts, 241, 101)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 243, 27)) +>column : Symbol(column, Decl(controlFlowGenericTypes.ts, 243, 30)) +>Column : Symbol(Column, Decl(controlFlowGenericTypes.ts, 237, 1)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 243, 27)) +>key : Symbol(key, Decl(controlFlowGenericTypes.ts, 243, 48)) +>Column : Symbol(Column, Decl(controlFlowGenericTypes.ts, 237, 1)) +>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 243, 27)) return column[key]; ->column : Symbol(column, Decl(controlFlowGenericTypes.ts, 216, 30)) ->key : Symbol(key, Decl(controlFlowGenericTypes.ts, 216, 48)) +>column : Symbol(column, Decl(controlFlowGenericTypes.ts, 243, 30)) +>key : Symbol(key, Decl(controlFlowGenericTypes.ts, 243, 48)) } diff --git a/tests/baselines/reference/controlFlowGenericTypes.types b/tests/baselines/reference/controlFlowGenericTypes.types index 34aaf80709138..2eaff9186c40c 100644 --- a/tests/baselines/reference/controlFlowGenericTypes.types +++ b/tests/baselines/reference/controlFlowGenericTypes.types @@ -583,9 +583,9 @@ function once>(emittingObject: T, eventName: keyo > : ^ } -// In an element access obj[x], we consider obj to be in a constraint position, except when obj is of -// a generic type without a nullable constraint and x is a generic type. This is because when both obj -// and x are of generic types T and K, we want the resulting type to be T[K]. +// In an element access obj[key], we consider obj to be in a constraint position, except when +// obj and key both have generic types. When obj and key are of generic types T and K, we want +// the resulting type to be T[K]. function fx1(obj: T, key: K) { >fx1 : (obj: T, key: K) => void @@ -617,6 +617,16 @@ function fx1(obj: T, key: K) { >obj : NonNullable > : ^^^^^^^^^^^^^^ >key : K +> : ^ + + const x3 = obj?.[key]; +>x3 : NonNullable[K] | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>obj?.[key] : NonNullable[K] | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>obj : T +> : ^ +>key : K > : ^ } @@ -650,6 +660,16 @@ function fx2, K extends keyof T>(obj: T, key: >obj : T > : ^ >key : K +> : ^ + + const x3 = obj?.[key]; +>x3 : T[K] +> : ^^^^ +>obj?.[key] : T[K] +> : ^^^^ +>obj : T +> : ^ +>key : K > : ^ } @@ -661,27 +681,223 @@ function fx3 | undefined, K extends keyof T>(o >key : K > : ^ - const x1 = obj[key]; // Error ->x1 : Record[K] -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^ ->obj[key] : Record[K] -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^ ->obj : Record | undefined -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + const x1 = obj[key]; +>x1 : T[K] +> : ^^^^ +>obj[key] : T[K] +> : ^^^^ +>obj : T +> : ^ >key : K > : ^ const x2 = obj && obj[key]; ->x2 : Record[K] -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^ ->obj && obj[key] : Record[K] -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^ +>x2 : NonNullable[K] +> : ^^^^^^^^^^^^^^^^^ +>obj && obj[key] : NonNullable[K] +> : ^^^^^^^^^^^^^^^^^ +>obj : T +> : ^ +>obj[key] : NonNullable[K] +> : ^^^^^^^^^^^^^^^^^ +>obj : NonNullable +> : ^^^^^^^^^^^^^^ +>key : K +> : ^ + + const x3 = obj?.[key]; +>x3 : NonNullable[K] | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>obj?.[key] : NonNullable[K] | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >obj : T > : ^ ->obj[key] : Record[K] -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^ ->obj : Record -> : ^^^^^^^^^^^^^^^^^^^^^^^ +>key : K +> : ^ +} + +function fx4(obj: T, key: K) { +>fx4 : (obj: T, key: K) => void +> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^^^^^ +>obj : T +> : ^ +>key : K +> : ^ + + const x1 = obj[key]; +>x1 : T[K] +> : ^^^^ +>obj[key] : T[K] +> : ^^^^ +>obj : T +> : ^ +>key : K +> : ^ + + const x2 = obj && obj[key]; +>x2 : NonNullable[K] +> : ^^^^^^^^^^^^^^^^^ +>obj && obj[key] : NonNullable[K] +> : ^^^^^^^^^^^^^^^^^ +>obj : T +> : ^ +>obj[key] : NonNullable[K] +> : ^^^^^^^^^^^^^^^^^ +>obj : NonNullable +> : ^^^^^^^^^^^^^^ +>key : K +> : ^ + + const x3 = obj?.[key]; +>x3 : NonNullable[K] | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>obj?.[key] : NonNullable[K] | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>obj : T +> : ^ +>key : K +> : ^ +} + +function fx5(obj: T, key: K) { +>fx5 : (obj: T, key: K) => void +> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^^^^^ +>obj : T +> : ^ +>key : K +> : ^ + + const x1 = obj[key]; +>x1 : T[K] +> : ^^^^ +>obj[key] : T[K] +> : ^^^^ +>obj : T +> : ^ +>key : K +> : ^ + + const x2 = obj && obj[key]; +>x2 : NonNullable[K] +> : ^^^^^^^^^^^^^^^^^ +>obj && obj[key] : NonNullable[K] +> : ^^^^^^^^^^^^^^^^^ +>obj : T +> : ^ +>obj[key] : NonNullable[K] +> : ^^^^^^^^^^^^^^^^^ +>obj : NonNullable +> : ^^^^^^^^^^^^^^ +>key : K +> : ^ + + const x3 = obj?.[key]; +>x3 : NonNullable[K] | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>obj?.[key] : NonNullable[K] | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>obj : T +> : ^ +>key : K +> : ^ +} + +function fx6(obj: T | null | undefined, key: K) { +>fx6 : (obj: T | null | undefined, key: K) => void +> : ^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^^^^^ +>obj : T | null | undefined +> : ^^^^^^^^^^^^^^^^^^^^ +>key : K +> : ^ + + const x1 = obj[key]; // Error +>x1 : NonNullable[K] +> : ^^^^^^^^^^^^^^^^^ +>obj[key] : NonNullable[K] +> : ^^^^^^^^^^^^^^^^^ +>obj : T | null | undefined +> : ^^^^^^^^^^^^^^^^^^^^ +>key : K +> : ^ + + const x2 = obj && obj[key]; +>x2 : NonNullable[K] | null | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>obj && obj[key] : NonNullable[K] | null | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>obj : T | null | undefined +> : ^^^^^^^^^^^^^^^^^^^^ +>obj[key] : NonNullable[K] +> : ^^^^^^^^^^^^^^^^^ +>obj : NonNullable +> : ^^^^^^^^^^^^^^ +>key : K +> : ^ + + const x3 = obj?.[key]; +>x3 : NonNullable[K] | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>obj?.[key] : NonNullable[K] | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>obj : T | null | undefined +> : ^^^^^^^^^^^^^^^^^^^^ +>key : K +> : ^ +} + +function fx7(obj: { x: T } | null | undefined, key: K) { +>fx7 : (obj: { x: T; } | null | undefined, key: K) => void +> : ^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^^^^^ +>obj : { x: T; } | null | undefined +> : ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^ +>x : T +> : ^ +>key : K +> : ^ + + const x1 = obj.x[key]; // Error +>x1 : T[K] +> : ^^^^ +>obj.x[key] : T[K] +> : ^^^^ +>obj.x : T +> : ^ +>obj : { x: T; } | null | undefined +> : ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^ +>x : T +> : ^ +>key : K +> : ^ + + const x2 = obj && obj.x[key]; +>x2 : T[K] | null | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^ +>obj && obj.x[key] : T[K] | null | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^ +>obj : { x: T; } | null | undefined +> : ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^ +>obj.x[key] : T[K] +> : ^^^^ +>obj.x : T +> : ^ +>obj : { x: T; } +> : ^^^^^ ^^^ +>x : T +> : ^ +>key : K +> : ^ + + const x3 = obj?.x[key]; +>x3 : T[K] | undefined +> : ^^^^^^^^^^^^^^^^ +>obj?.x[key] : T[K] | undefined +> : ^^^^^^^^^^^^^^^^ +>obj?.x : T | undefined +> : ^^^^^^^^^^^^^ +>obj : { x: T; } | null | undefined +> : ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^ +>x : T | undefined +> : ^^^^^^^^^^^^^ >key : K > : ^ } @@ -706,21 +922,21 @@ class TableBaseEnum< >null! : never > : ^^^^^ - iSpec[null! as keyof InternalSpec]; // Error, object possibly undefined ->iSpec[null! as keyof InternalSpec] : Record[keyof InternalSpec] -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->iSpec : Record | undefined -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + iSpec[null! as keyof InternalSpec]; +>iSpec[null! as keyof InternalSpec] : InternalSpec[keyof InternalSpec] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>iSpec : InternalSpec +> : ^^^^^^^^^^^^ >null! as keyof InternalSpec : keyof InternalSpec > : ^^^^^^^^^^^^^^^^^^ >null! : never > : ^^^^^ - iSpec[null! as keyof PublicSpec]; // Error, object possibly undefined ->iSpec[null! as keyof PublicSpec] : Record[keyof PublicSpec] -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->iSpec : Record | undefined -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + iSpec[null! as keyof PublicSpec]; // Error +>iSpec[null! as keyof PublicSpec] : any +> : ^^^ +>iSpec : InternalSpec +> : ^^^^^^^^^^^^ >null! as keyof PublicSpec : keyof PublicSpec > : ^^^^^^^^^^^^^^^^ >null! : never @@ -737,20 +953,20 @@ class TableBaseEnum< return; } iSpec[null! as keyof InternalSpec]; ->iSpec[null! as keyof InternalSpec] : Record[keyof InternalSpec] -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->iSpec : Record -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>iSpec[null! as keyof InternalSpec] : (InternalSpec & {})[keyof InternalSpec] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>iSpec : InternalSpec & {} +> : ^^^^^^^^^^^^^^^^^ >null! as keyof InternalSpec : keyof InternalSpec > : ^^^^^^^^^^^^^^^^^^ >null! : never > : ^^^^^ iSpec[null! as keyof PublicSpec]; ->iSpec[null! as keyof PublicSpec] : Record[keyof PublicSpec] -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->iSpec : Record -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>iSpec[null! as keyof PublicSpec] : (InternalSpec & {})[keyof PublicSpec] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>iSpec : InternalSpec & {} +> : ^^^^^^^^^^^^^^^^^ >null! as keyof PublicSpec : keyof PublicSpec > : ^^^^^^^^^^^^^^^^ >null! : never diff --git a/tests/cases/conformance/controlFlow/controlFlowGenericTypes.ts b/tests/cases/conformance/controlFlow/controlFlowGenericTypes.ts index 50c2c4fdf147e..d4dcd885a4516 100644 --- a/tests/cases/conformance/controlFlow/controlFlowGenericTypes.ts +++ b/tests/cases/conformance/controlFlow/controlFlowGenericTypes.ts @@ -140,23 +140,50 @@ function once>(emittingObject: T, eventName: keyo emittingObject.off(eventName as typeof eventName, 0); } -// In an element access obj[x], we consider obj to be in a constraint position, except when obj is of -// a generic type without a nullable constraint and x is a generic type. This is because when both obj -// and x are of generic types T and K, we want the resulting type to be T[K]. +// In an element access obj[key], we consider obj to be in a constraint position, except when +// obj and key both have generic types. When obj and key are of generic types T and K, we want +// the resulting type to be T[K]. function fx1(obj: T, key: K) { const x1 = obj[key]; const x2 = obj && obj[key]; + const x3 = obj?.[key]; } function fx2, K extends keyof T>(obj: T, key: K) { const x1 = obj[key]; const x2 = obj && obj[key]; + const x3 = obj?.[key]; } function fx3 | undefined, K extends keyof T>(obj: T, key: K) { + const x1 = obj[key]; + const x2 = obj && obj[key]; + const x3 = obj?.[key]; +} + +function fx4(obj: T, key: K) { + const x1 = obj[key]; + const x2 = obj && obj[key]; + const x3 = obj?.[key]; +} + +function fx5(obj: T, key: K) { + const x1 = obj[key]; + const x2 = obj && obj[key]; + const x3 = obj?.[key]; +} + +function fx6(obj: T | null | undefined, key: K) { const x1 = obj[key]; // Error const x2 = obj && obj[key]; + const x3 = obj?.[key]; +} + +function fx7(obj: { x: T } | null | undefined, key: K) { + const x1 = obj.x[key]; // Error + const x2 = obj && obj.x[key]; + const x3 = obj?.x[key]; } // Repro from #44166 @@ -166,8 +193,8 @@ class TableBaseEnum< InternalSpec extends Record | undefined = undefined> { m() { let iSpec = null! as InternalSpec; - iSpec[null! as keyof InternalSpec]; // Error, object possibly undefined - iSpec[null! as keyof PublicSpec]; // Error, object possibly undefined + iSpec[null! as keyof InternalSpec]; + iSpec[null! as keyof PublicSpec]; // Error if (iSpec === undefined) { return; }