mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 12:08:41 -06:00
Correctly compute noUncheckedIndexedAccess effects on compound/increment/decrement assignments (#58239)
This commit is contained in:
parent
3480321b38
commit
aedd1b1bb5
@ -33031,7 +33031,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
error(node, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(apparentType));
|
||||
}
|
||||
|
||||
propType = (compilerOptions.noUncheckedIndexedAccess && !isAssignmentTarget(node)) ? getUnionType([indexInfo.type, missingType]) : indexInfo.type;
|
||||
propType = indexInfo.type;
|
||||
if (compilerOptions.noUncheckedIndexedAccess && getAssignmentTargetKind(node) !== AssignmentKind.Definite) {
|
||||
propType = getUnionType([propType, missingType]);
|
||||
}
|
||||
if (compilerOptions.noPropertyAccessFromIndexSignature && isPropertyAccessExpression(node)) {
|
||||
error(right, Diagnostics.Property_0_comes_from_an_index_signature_so_it_must_be_accessed_with_0, unescapeLeadingUnderscores(right.escapedText));
|
||||
}
|
||||
@ -33626,9 +33629,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
|
||||
const effectiveIndexType = isForInVariableForNumericPropertyNames(indexExpression) ? numberType : indexType;
|
||||
const accessFlags = isAssignmentTarget(node) ?
|
||||
AccessFlags.Writing | (isGenericObjectType(objectType) && !isThisTypeParameter(objectType) ? AccessFlags.NoIndexSignatures : 0) :
|
||||
AccessFlags.ExpressionPosition;
|
||||
const assignmentTargetKind = getAssignmentTargetKind(node);
|
||||
let accessFlags: AccessFlags;
|
||||
if (assignmentTargetKind === AssignmentKind.None) {
|
||||
accessFlags = AccessFlags.ExpressionPosition;
|
||||
}
|
||||
else {
|
||||
accessFlags = AccessFlags.Writing | (isGenericObjectType(objectType) && !isThisTypeParameter(objectType) ? AccessFlags.NoIndexSignatures : 0);
|
||||
if (assignmentTargetKind === AssignmentKind.Compound) {
|
||||
accessFlags |= AccessFlags.ExpressionPosition;
|
||||
}
|
||||
}
|
||||
const indexedAccessType = getIndexedAccessTypeOrUndefined(objectType, effectiveIndexType, accessFlags, node) || errorType;
|
||||
return checkIndexedAccessIndexType(getFlowTypeOfAccessExpression(node, getNodeLinks(node).resolvedSymbol, indexedAccessType, indexExpression, checkMode), node);
|
||||
}
|
||||
|
||||
@ -0,0 +1,59 @@
|
||||
noUncheckedIndexedAccessCompoundAssignments.ts(3,1): error TS18048: 'stringMap.foo' is possibly 'undefined'.
|
||||
noUncheckedIndexedAccessCompoundAssignments.ts(4,3): error TS18048: 'stringMap.foo' is possibly 'undefined'.
|
||||
noUncheckedIndexedAccessCompoundAssignments.ts(5,1): error TS18048: 'stringMap.foo' is possibly 'undefined'.
|
||||
noUncheckedIndexedAccessCompoundAssignments.ts(6,1): error TS18048: 'stringMap.foo' is possibly 'undefined'.
|
||||
noUncheckedIndexedAccessCompoundAssignments.ts(7,3): error TS2532: Object is possibly 'undefined'.
|
||||
noUncheckedIndexedAccessCompoundAssignments.ts(8,1): error TS2532: Object is possibly 'undefined'.
|
||||
noUncheckedIndexedAccessCompoundAssignments.ts(9,3): error TS2532: Object is possibly 'undefined'.
|
||||
noUncheckedIndexedAccessCompoundAssignments.ts(10,1): error TS2532: Object is possibly 'undefined'.
|
||||
noUncheckedIndexedAccessCompoundAssignments.ts(11,1): error TS2532: Object is possibly 'undefined'.
|
||||
noUncheckedIndexedAccessCompoundAssignments.ts(12,1): error TS2532: Object is possibly 'undefined'.
|
||||
noUncheckedIndexedAccessCompoundAssignments.ts(13,1): error TS2532: Object is possibly 'undefined'.
|
||||
noUncheckedIndexedAccessCompoundAssignments.ts(14,1): error TS2532: Object is possibly 'undefined'.
|
||||
|
||||
|
||||
==== noUncheckedIndexedAccessCompoundAssignments.ts (12 errors) ====
|
||||
// Each line should have one error
|
||||
// for a total of 12 errors
|
||||
stringMap.foo++;
|
||||
~~~~~~~~~~~~~
|
||||
!!! error TS18048: 'stringMap.foo' is possibly 'undefined'.
|
||||
--stringMap.foo;
|
||||
~~~~~~~~~~~~~
|
||||
!!! error TS18048: 'stringMap.foo' is possibly 'undefined'.
|
||||
stringMap.foo += 1;
|
||||
~~~~~~~~~~~~~
|
||||
!!! error TS18048: 'stringMap.foo' is possibly 'undefined'.
|
||||
stringMap.foo *= 1;
|
||||
~~~~~~~~~~~~~
|
||||
!!! error TS18048: 'stringMap.foo' is possibly 'undefined'.
|
||||
++stringMap['foo'];
|
||||
~~~~~~~~~~~~~~~~
|
||||
!!! error TS2532: Object is possibly 'undefined'.
|
||||
stringMap['foo']--;
|
||||
~~~~~~~~~~~~~~~~
|
||||
!!! error TS2532: Object is possibly 'undefined'.
|
||||
++stringMap[s];
|
||||
~~~~~~~~~~~~
|
||||
!!! error TS2532: Object is possibly 'undefined'.
|
||||
stringMap[s]--;
|
||||
~~~~~~~~~~~~
|
||||
!!! error TS2532: Object is possibly 'undefined'.
|
||||
numberMap[32]++;
|
||||
~~~~~~~~~~~~~
|
||||
!!! error TS2532: Object is possibly 'undefined'.
|
||||
numberMap[32] += 1;
|
||||
~~~~~~~~~~~~~
|
||||
!!! error TS2532: Object is possibly 'undefined'.
|
||||
numberMap[n]++;
|
||||
~~~~~~~~~~~~
|
||||
!!! error TS2532: Object is possibly 'undefined'.
|
||||
numberMap[n] += 1;
|
||||
~~~~~~~~~~~~
|
||||
!!! error TS2532: Object is possibly 'undefined'.
|
||||
|
||||
declare const stringMap: { [s: string]: number };
|
||||
declare const s: string;
|
||||
declare const numberMap: { [n: number]: number };
|
||||
declare const n: number;
|
||||
|
||||
@ -0,0 +1,40 @@
|
||||
//// [tests/cases/compiler/noUncheckedIndexedAccessCompoundAssignments.ts] ////
|
||||
|
||||
//// [noUncheckedIndexedAccessCompoundAssignments.ts]
|
||||
// Each line should have one error
|
||||
// for a total of 12 errors
|
||||
stringMap.foo++;
|
||||
--stringMap.foo;
|
||||
stringMap.foo += 1;
|
||||
stringMap.foo *= 1;
|
||||
++stringMap['foo'];
|
||||
stringMap['foo']--;
|
||||
++stringMap[s];
|
||||
stringMap[s]--;
|
||||
numberMap[32]++;
|
||||
numberMap[32] += 1;
|
||||
numberMap[n]++;
|
||||
numberMap[n] += 1;
|
||||
|
||||
declare const stringMap: { [s: string]: number };
|
||||
declare const s: string;
|
||||
declare const numberMap: { [n: number]: number };
|
||||
declare const n: number;
|
||||
|
||||
|
||||
//// [noUncheckedIndexedAccessCompoundAssignments.js]
|
||||
"use strict";
|
||||
// Each line should have one error
|
||||
// for a total of 12 errors
|
||||
stringMap.foo++;
|
||||
--stringMap.foo;
|
||||
stringMap.foo += 1;
|
||||
stringMap.foo *= 1;
|
||||
++stringMap['foo'];
|
||||
stringMap['foo']--;
|
||||
++stringMap[s];
|
||||
stringMap[s]--;
|
||||
numberMap[32]++;
|
||||
numberMap[32] += 1;
|
||||
numberMap[n]++;
|
||||
numberMap[n] += 1;
|
||||
@ -0,0 +1,67 @@
|
||||
//// [tests/cases/compiler/noUncheckedIndexedAccessCompoundAssignments.ts] ////
|
||||
|
||||
=== noUncheckedIndexedAccessCompoundAssignments.ts ===
|
||||
// Each line should have one error
|
||||
// for a total of 12 errors
|
||||
stringMap.foo++;
|
||||
>stringMap.foo : Symbol(__index, Decl(noUncheckedIndexedAccessCompoundAssignments.ts, 15, 26))
|
||||
>stringMap : Symbol(stringMap, Decl(noUncheckedIndexedAccessCompoundAssignments.ts, 15, 13))
|
||||
>foo : Symbol(__index, Decl(noUncheckedIndexedAccessCompoundAssignments.ts, 15, 26))
|
||||
|
||||
--stringMap.foo;
|
||||
>stringMap.foo : Symbol(__index, Decl(noUncheckedIndexedAccessCompoundAssignments.ts, 15, 26))
|
||||
>stringMap : Symbol(stringMap, Decl(noUncheckedIndexedAccessCompoundAssignments.ts, 15, 13))
|
||||
>foo : Symbol(__index, Decl(noUncheckedIndexedAccessCompoundAssignments.ts, 15, 26))
|
||||
|
||||
stringMap.foo += 1;
|
||||
>stringMap.foo : Symbol(__index, Decl(noUncheckedIndexedAccessCompoundAssignments.ts, 15, 26))
|
||||
>stringMap : Symbol(stringMap, Decl(noUncheckedIndexedAccessCompoundAssignments.ts, 15, 13))
|
||||
>foo : Symbol(__index, Decl(noUncheckedIndexedAccessCompoundAssignments.ts, 15, 26))
|
||||
|
||||
stringMap.foo *= 1;
|
||||
>stringMap.foo : Symbol(__index, Decl(noUncheckedIndexedAccessCompoundAssignments.ts, 15, 26))
|
||||
>stringMap : Symbol(stringMap, Decl(noUncheckedIndexedAccessCompoundAssignments.ts, 15, 13))
|
||||
>foo : Symbol(__index, Decl(noUncheckedIndexedAccessCompoundAssignments.ts, 15, 26))
|
||||
|
||||
++stringMap['foo'];
|
||||
>stringMap : Symbol(stringMap, Decl(noUncheckedIndexedAccessCompoundAssignments.ts, 15, 13))
|
||||
|
||||
stringMap['foo']--;
|
||||
>stringMap : Symbol(stringMap, Decl(noUncheckedIndexedAccessCompoundAssignments.ts, 15, 13))
|
||||
|
||||
++stringMap[s];
|
||||
>stringMap : Symbol(stringMap, Decl(noUncheckedIndexedAccessCompoundAssignments.ts, 15, 13))
|
||||
>s : Symbol(s, Decl(noUncheckedIndexedAccessCompoundAssignments.ts, 16, 13))
|
||||
|
||||
stringMap[s]--;
|
||||
>stringMap : Symbol(stringMap, Decl(noUncheckedIndexedAccessCompoundAssignments.ts, 15, 13))
|
||||
>s : Symbol(s, Decl(noUncheckedIndexedAccessCompoundAssignments.ts, 16, 13))
|
||||
|
||||
numberMap[32]++;
|
||||
>numberMap : Symbol(numberMap, Decl(noUncheckedIndexedAccessCompoundAssignments.ts, 17, 13))
|
||||
|
||||
numberMap[32] += 1;
|
||||
>numberMap : Symbol(numberMap, Decl(noUncheckedIndexedAccessCompoundAssignments.ts, 17, 13))
|
||||
|
||||
numberMap[n]++;
|
||||
>numberMap : Symbol(numberMap, Decl(noUncheckedIndexedAccessCompoundAssignments.ts, 17, 13))
|
||||
>n : Symbol(n, Decl(noUncheckedIndexedAccessCompoundAssignments.ts, 18, 13))
|
||||
|
||||
numberMap[n] += 1;
|
||||
>numberMap : Symbol(numberMap, Decl(noUncheckedIndexedAccessCompoundAssignments.ts, 17, 13))
|
||||
>n : Symbol(n, Decl(noUncheckedIndexedAccessCompoundAssignments.ts, 18, 13))
|
||||
|
||||
declare const stringMap: { [s: string]: number };
|
||||
>stringMap : Symbol(stringMap, Decl(noUncheckedIndexedAccessCompoundAssignments.ts, 15, 13))
|
||||
>s : Symbol(s, Decl(noUncheckedIndexedAccessCompoundAssignments.ts, 15, 28))
|
||||
|
||||
declare const s: string;
|
||||
>s : Symbol(s, Decl(noUncheckedIndexedAccessCompoundAssignments.ts, 16, 13))
|
||||
|
||||
declare const numberMap: { [n: number]: number };
|
||||
>numberMap : Symbol(numberMap, Decl(noUncheckedIndexedAccessCompoundAssignments.ts, 17, 13))
|
||||
>n : Symbol(n, Decl(noUncheckedIndexedAccessCompoundAssignments.ts, 17, 28))
|
||||
|
||||
declare const n: number;
|
||||
>n : Symbol(n, Decl(noUncheckedIndexedAccessCompoundAssignments.ts, 18, 13))
|
||||
|
||||
@ -0,0 +1,153 @@
|
||||
//// [tests/cases/compiler/noUncheckedIndexedAccessCompoundAssignments.ts] ////
|
||||
|
||||
=== noUncheckedIndexedAccessCompoundAssignments.ts ===
|
||||
// Each line should have one error
|
||||
// for a total of 12 errors
|
||||
stringMap.foo++;
|
||||
>stringMap.foo++ : number
|
||||
> : ^^^^^^
|
||||
>stringMap.foo : number | undefined
|
||||
> : ^^^^^^^^^^^^^^^^^^
|
||||
>stringMap : { [s: string]: number; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>foo : number | undefined
|
||||
> : ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
--stringMap.foo;
|
||||
>--stringMap.foo : number
|
||||
> : ^^^^^^
|
||||
>stringMap.foo : number | undefined
|
||||
> : ^^^^^^^^^^^^^^^^^^
|
||||
>stringMap : { [s: string]: number; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>foo : number | undefined
|
||||
> : ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
stringMap.foo += 1;
|
||||
>stringMap.foo += 1 : number
|
||||
> : ^^^^^^
|
||||
>stringMap.foo : number | undefined
|
||||
> : ^^^^^^^^^^^^^^^^^^
|
||||
>stringMap : { [s: string]: number; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>foo : number | undefined
|
||||
> : ^^^^^^^^^^^^^^^^^^
|
||||
>1 : 1
|
||||
> : ^
|
||||
|
||||
stringMap.foo *= 1;
|
||||
>stringMap.foo *= 1 : number
|
||||
> : ^^^^^^
|
||||
>stringMap.foo : number | undefined
|
||||
> : ^^^^^^^^^^^^^^^^^^
|
||||
>stringMap : { [s: string]: number; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>foo : number | undefined
|
||||
> : ^^^^^^^^^^^^^^^^^^
|
||||
>1 : 1
|
||||
> : ^
|
||||
|
||||
++stringMap['foo'];
|
||||
>++stringMap['foo'] : number
|
||||
> : ^^^^^^
|
||||
>stringMap['foo'] : number | undefined
|
||||
> : ^^^^^^^^^^^^^^^^^^
|
||||
>stringMap : { [s: string]: number; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>'foo' : "foo"
|
||||
> : ^^^^^
|
||||
|
||||
stringMap['foo']--;
|
||||
>stringMap['foo']-- : number
|
||||
> : ^^^^^^
|
||||
>stringMap['foo'] : number | undefined
|
||||
> : ^^^^^^^^^^^^^^^^^^
|
||||
>stringMap : { [s: string]: number; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>'foo' : "foo"
|
||||
> : ^^^^^
|
||||
|
||||
++stringMap[s];
|
||||
>++stringMap[s] : number
|
||||
> : ^^^^^^
|
||||
>stringMap[s] : number | undefined
|
||||
> : ^^^^^^^^^^^^^^^^^^
|
||||
>stringMap : { [s: string]: number; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>s : string
|
||||
> : ^^^^^^
|
||||
|
||||
stringMap[s]--;
|
||||
>stringMap[s]-- : number
|
||||
> : ^^^^^^
|
||||
>stringMap[s] : number | undefined
|
||||
> : ^^^^^^^^^^^^^^^^^^
|
||||
>stringMap : { [s: string]: number; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>s : string
|
||||
> : ^^^^^^
|
||||
|
||||
numberMap[32]++;
|
||||
>numberMap[32]++ : number
|
||||
> : ^^^^^^
|
||||
>numberMap[32] : number | undefined
|
||||
> : ^^^^^^^^^^^^^^^^^^
|
||||
>numberMap : { [n: number]: number; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>32 : 32
|
||||
> : ^^
|
||||
|
||||
numberMap[32] += 1;
|
||||
>numberMap[32] += 1 : number
|
||||
> : ^^^^^^
|
||||
>numberMap[32] : number | undefined
|
||||
> : ^^^^^^^^^^^^^^^^^^
|
||||
>numberMap : { [n: number]: number; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>32 : 32
|
||||
> : ^^
|
||||
>1 : 1
|
||||
> : ^
|
||||
|
||||
numberMap[n]++;
|
||||
>numberMap[n]++ : number
|
||||
> : ^^^^^^
|
||||
>numberMap[n] : number | undefined
|
||||
> : ^^^^^^^^^^^^^^^^^^
|
||||
>numberMap : { [n: number]: number; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>n : number
|
||||
> : ^^^^^^
|
||||
|
||||
numberMap[n] += 1;
|
||||
>numberMap[n] += 1 : number
|
||||
> : ^^^^^^
|
||||
>numberMap[n] : number | undefined
|
||||
> : ^^^^^^^^^^^^^^^^^^
|
||||
>numberMap : { [n: number]: number; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>n : number
|
||||
> : ^^^^^^
|
||||
>1 : 1
|
||||
> : ^
|
||||
|
||||
declare const stringMap: { [s: string]: number };
|
||||
>stringMap : { [s: string]: number; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>s : string
|
||||
> : ^^^^^^
|
||||
|
||||
declare const s: string;
|
||||
>s : string
|
||||
> : ^^^^^^
|
||||
|
||||
declare const numberMap: { [n: number]: number };
|
||||
>numberMap : { [n: number]: number; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>n : number
|
||||
> : ^^^^^^
|
||||
|
||||
declare const n: number;
|
||||
>n : number
|
||||
> : ^^^^^^
|
||||
|
||||
@ -0,0 +1,22 @@
|
||||
// @strict: true
|
||||
// @noUncheckedIndexedAccess: true
|
||||
|
||||
// Each line should have one error
|
||||
// for a total of 12 errors
|
||||
stringMap.foo++;
|
||||
--stringMap.foo;
|
||||
stringMap.foo += 1;
|
||||
stringMap.foo *= 1;
|
||||
++stringMap['foo'];
|
||||
stringMap['foo']--;
|
||||
++stringMap[s];
|
||||
stringMap[s]--;
|
||||
numberMap[32]++;
|
||||
numberMap[32] += 1;
|
||||
numberMap[n]++;
|
||||
numberMap[n] += 1;
|
||||
|
||||
declare const stringMap: { [s: string]: number };
|
||||
declare const s: string;
|
||||
declare const numberMap: { [n: number]: number };
|
||||
declare const n: number;
|
||||
Loading…
x
Reference in New Issue
Block a user