-
Notifications
You must be signed in to change notification settings - Fork 12.8k
--noUncheckedIndexedAccess #39560
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
andrewbranch
merged 11 commits into
microsoft:master
from
RyanCavanaugh:pedanticIndexSignatures
Sep 11, 2020
Merged
--noUncheckedIndexedAccess #39560
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
661740f
Initial implementation + tests
RyanCavanaugh 6d1ec2b
linty
RyanCavanaugh 6a1e284
Support destructuring declarations and assignments
RyanCavanaugh 6218d97
lint
RyanCavanaugh 186d9d3
Fix destructuring assignment and element access into known properties
andrewbranch 8366df3
Update baselines
andrewbranch 0f25ce9
Rename flag to unUncheckedIndexedAccess
andrewbranch 82190c1
Add test for unique symbol indexing
andrewbranch c446e4d
Merge branch 'master' into pedanticIndexSignatures
andrewbranch 6dbb8f5
Merge branch 'master' into pedanticIndexSignatures
andrewbranch 544b69a
Fix flag order in baselines
andrewbranch File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
109 changes: 109 additions & 0 deletions
109
tests/baselines/reference/noUncheckedIndexedAccess.errors.txt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
tests/cases/conformance/pedantic/noUncheckedIndexedAccess.ts(3,32): error TS2344: Type 'boolean | undefined' does not satisfy the constraint 'boolean'. | ||
Type 'undefined' is not assignable to type 'boolean'. | ||
tests/cases/conformance/pedantic/noUncheckedIndexedAccess.ts(38,1): error TS2322: Type 'undefined' is not assignable to type 'boolean'. | ||
tests/cases/conformance/pedantic/noUncheckedIndexedAccess.ts(39,1): error TS2322: Type 'undefined' is not assignable to type 'boolean'. | ||
tests/cases/conformance/pedantic/noUncheckedIndexedAccess.ts(40,1): error TS2322: Type 'undefined' is not assignable to type 'boolean'. | ||
tests/cases/conformance/pedantic/noUncheckedIndexedAccess.ts(41,1): error TS2322: Type 'undefined' is not assignable to type 'boolean'. | ||
tests/cases/conformance/pedantic/noUncheckedIndexedAccess.ts(85,1): error TS2322: Type 'undefined' is not assignable to type 'string'. | ||
|
||
|
||
==== tests/cases/conformance/pedantic/noUncheckedIndexedAccess.ts (6 errors) ==== | ||
type CheckBooleanOnly<T extends boolean> = any; | ||
// Validate CheckBooleanOnly works - should error | ||
type T_ERR1 = CheckBooleanOnly<boolean | undefined>; | ||
~~~~~~~~~~~~~~~~~~~ | ||
!!! error TS2344: Type 'boolean | undefined' does not satisfy the constraint 'boolean'. | ||
!!! error TS2344: Type 'undefined' is not assignable to type 'boolean'. | ||
|
||
enum NumericEnum1 { A, B, C } | ||
enum NumericEnum2 { A = 0, B = 1 , C = 2 } | ||
enum StringEnum1 { A = "Alpha", B = "Beta" } | ||
|
||
declare const strMap: { [s: string]: boolean }; | ||
|
||
// All of these should be errors | ||
const e1: boolean = strMap["foo"]; | ||
const e2: boolean = strMap.bar; | ||
const e3: boolean = strMap[0]; | ||
const e4: boolean = strMap[0 as string | number]; | ||
const e5: boolean = strMap[0 as string | 0 | 1]; | ||
const e6: boolean = strMap[0 as 0 | 1]; | ||
const e7: boolean = strMap["foo" as "foo" | "baz"]; | ||
const e8: boolean = strMap[NumericEnum1.A]; | ||
const e9: boolean = strMap[NumericEnum2.A]; | ||
const e10: boolean = strMap[StringEnum1.A]; | ||
const e11: boolean = strMap[StringEnum1.A as StringEnum1]; | ||
const e12: boolean = strMap[NumericEnum1.A as NumericEnum1]; | ||
const e13: boolean = strMap[NumericEnum2.A as NumericEnum2]; | ||
const e14: boolean = strMap[null as any]; | ||
|
||
// Should be OK | ||
const ok1: boolean | undefined = strMap["foo"]; | ||
const ok2: boolean | undefined = strMap.bar; | ||
|
||
type T_OK1 = CheckBooleanOnly<(typeof strMap)[string]>; | ||
type T_OK2 = CheckBooleanOnly<(typeof strMap)["foo"]>; | ||
type T_OK3 = CheckBooleanOnly<(typeof strMap)["bar" | "baz"]>; | ||
type T_OK4 = CheckBooleanOnly<(typeof strMap)[number]>; | ||
type T_OK5 = CheckBooleanOnly<(typeof strMap)[any]>; | ||
|
||
// Writes don't allow 'undefined'; all should be errors | ||
strMap["baz"] = undefined; | ||
~~~~~~~~~~~~~ | ||
!!! error TS2322: Type 'undefined' is not assignable to type 'boolean'. | ||
strMap.qua = undefined; | ||
~~~~~~~~~~ | ||
!!! error TS2322: Type 'undefined' is not assignable to type 'boolean'. | ||
strMap[0] = undefined; | ||
~~~~~~~~~ | ||
!!! error TS2322: Type 'undefined' is not assignable to type 'boolean'. | ||
strMap[null as any] = undefined; | ||
~~~~~~~~~~~~~~~~~~~ | ||
!!! error TS2322: Type 'undefined' is not assignable to type 'boolean'. | ||
|
||
// Numeric lookups are unaffected | ||
declare const numMap: { [s: number]: boolean }; | ||
// All of these should be ok | ||
const num_ok1: boolean = numMap[0]; | ||
const num_ok2: boolean = numMap[0 as number]; | ||
const num_ok3: boolean = numMap[0 as 0 | 1]; | ||
const num_ok4: boolean = numMap[NumericEnum1.A]; | ||
const num_ok5: boolean = numMap[NumericEnum2.A]; | ||
|
||
// Generics | ||
function generic1<T extends { [s: string]: boolean }>(arg: T): boolean { | ||
// Should error | ||
return arg["blah"]; | ||
} | ||
function generic2<T extends { [s: string]: boolean }>(arg: T): boolean { | ||
// Should OK | ||
return arg["blah"]!; | ||
} | ||
function generic3<T extends string>(arg: T): boolean { | ||
// Should error | ||
return strMap[arg]; | ||
} | ||
|
||
// Element access into known properties is ok | ||
declare const obj1: { x: string, y: number, [key: string]: string | number }; | ||
obj1["x"]; | ||
const y = "y"; | ||
obj1[y]; | ||
let yy = "y"; | ||
obj1[yy]; | ||
let z = "z"; | ||
obj1[z]; | ||
|
||
// Distributivity cases | ||
declare const strMapUnion: { [s: string]: boolean } | { [s: string]: number }; | ||
// Should error | ||
const f1: boolean | number = strMapUnion["foo"]; | ||
|
||
// Symbol index signatures | ||
declare const s: unique symbol; | ||
declare const symbolMap: { [s]: string }; | ||
const e15: string = symbolMap[s]; // Should OK | ||
symbolMap[s] = undefined; // Should error | ||
~~~~~~~~~~~~ | ||
!!! error TS2322: Type 'undefined' is not assignable to type 'string'. | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
//// [noUncheckedIndexedAccess.ts] | ||
type CheckBooleanOnly<T extends boolean> = any; | ||
// Validate CheckBooleanOnly works - should error | ||
type T_ERR1 = CheckBooleanOnly<boolean | undefined>; | ||
|
||
enum NumericEnum1 { A, B, C } | ||
enum NumericEnum2 { A = 0, B = 1 , C = 2 } | ||
enum StringEnum1 { A = "Alpha", B = "Beta" } | ||
|
||
declare const strMap: { [s: string]: boolean }; | ||
|
||
// All of these should be errors | ||
const e1: boolean = strMap["foo"]; | ||
const e2: boolean = strMap.bar; | ||
const e3: boolean = strMap[0]; | ||
const e4: boolean = strMap[0 as string | number]; | ||
const e5: boolean = strMap[0 as string | 0 | 1]; | ||
const e6: boolean = strMap[0 as 0 | 1]; | ||
const e7: boolean = strMap["foo" as "foo" | "baz"]; | ||
const e8: boolean = strMap[NumericEnum1.A]; | ||
const e9: boolean = strMap[NumericEnum2.A]; | ||
const e10: boolean = strMap[StringEnum1.A]; | ||
const e11: boolean = strMap[StringEnum1.A as StringEnum1]; | ||
const e12: boolean = strMap[NumericEnum1.A as NumericEnum1]; | ||
const e13: boolean = strMap[NumericEnum2.A as NumericEnum2]; | ||
const e14: boolean = strMap[null as any]; | ||
|
||
// Should be OK | ||
const ok1: boolean | undefined = strMap["foo"]; | ||
const ok2: boolean | undefined = strMap.bar; | ||
|
||
type T_OK1 = CheckBooleanOnly<(typeof strMap)[string]>; | ||
type T_OK2 = CheckBooleanOnly<(typeof strMap)["foo"]>; | ||
type T_OK3 = CheckBooleanOnly<(typeof strMap)["bar" | "baz"]>; | ||
type T_OK4 = CheckBooleanOnly<(typeof strMap)[number]>; | ||
type T_OK5 = CheckBooleanOnly<(typeof strMap)[any]>; | ||
|
||
// Writes don't allow 'undefined'; all should be errors | ||
strMap["baz"] = undefined; | ||
strMap.qua = undefined; | ||
strMap[0] = undefined; | ||
strMap[null as any] = undefined; | ||
|
||
// Numeric lookups are unaffected | ||
declare const numMap: { [s: number]: boolean }; | ||
// All of these should be ok | ||
const num_ok1: boolean = numMap[0]; | ||
const num_ok2: boolean = numMap[0 as number]; | ||
const num_ok3: boolean = numMap[0 as 0 | 1]; | ||
const num_ok4: boolean = numMap[NumericEnum1.A]; | ||
const num_ok5: boolean = numMap[NumericEnum2.A]; | ||
|
||
// Generics | ||
function generic1<T extends { [s: string]: boolean }>(arg: T): boolean { | ||
// Should error | ||
return arg["blah"]; | ||
} | ||
function generic2<T extends { [s: string]: boolean }>(arg: T): boolean { | ||
// Should OK | ||
return arg["blah"]!; | ||
} | ||
function generic3<T extends string>(arg: T): boolean { | ||
// Should error | ||
return strMap[arg]; | ||
} | ||
|
||
// Element access into known properties is ok | ||
declare const obj1: { x: string, y: number, [key: string]: string | number }; | ||
obj1["x"]; | ||
const y = "y"; | ||
obj1[y]; | ||
let yy = "y"; | ||
obj1[yy]; | ||
let z = "z"; | ||
obj1[z]; | ||
|
||
// Distributivity cases | ||
declare const strMapUnion: { [s: string]: boolean } | { [s: string]: number }; | ||
// Should error | ||
const f1: boolean | number = strMapUnion["foo"]; | ||
|
||
// Symbol index signatures | ||
declare const s: unique symbol; | ||
declare const symbolMap: { [s]: string }; | ||
const e15: string = symbolMap[s]; // Should OK | ||
symbolMap[s] = undefined; // Should error | ||
|
||
|
||
//// [noUncheckedIndexedAccess.js] | ||
"use strict"; | ||
var NumericEnum1; | ||
(function (NumericEnum1) { | ||
NumericEnum1[NumericEnum1["A"] = 0] = "A"; | ||
NumericEnum1[NumericEnum1["B"] = 1] = "B"; | ||
NumericEnum1[NumericEnum1["C"] = 2] = "C"; | ||
})(NumericEnum1 || (NumericEnum1 = {})); | ||
var NumericEnum2; | ||
(function (NumericEnum2) { | ||
NumericEnum2[NumericEnum2["A"] = 0] = "A"; | ||
NumericEnum2[NumericEnum2["B"] = 1] = "B"; | ||
NumericEnum2[NumericEnum2["C"] = 2] = "C"; | ||
})(NumericEnum2 || (NumericEnum2 = {})); | ||
var StringEnum1; | ||
(function (StringEnum1) { | ||
StringEnum1["A"] = "Alpha"; | ||
StringEnum1["B"] = "Beta"; | ||
})(StringEnum1 || (StringEnum1 = {})); | ||
// All of these should be errors | ||
var e1 = strMap["foo"]; | ||
var e2 = strMap.bar; | ||
var e3 = strMap[0]; | ||
var e4 = strMap[0]; | ||
var e5 = strMap[0]; | ||
var e6 = strMap[0]; | ||
var e7 = strMap["foo"]; | ||
var e8 = strMap[NumericEnum1.A]; | ||
var e9 = strMap[NumericEnum2.A]; | ||
var e10 = strMap[StringEnum1.A]; | ||
var e11 = strMap[StringEnum1.A]; | ||
var e12 = strMap[NumericEnum1.A]; | ||
var e13 = strMap[NumericEnum2.A]; | ||
var e14 = strMap[null]; | ||
// Should be OK | ||
var ok1 = strMap["foo"]; | ||
var ok2 = strMap.bar; | ||
// Writes don't allow 'undefined'; all should be errors | ||
strMap["baz"] = undefined; | ||
strMap.qua = undefined; | ||
strMap[0] = undefined; | ||
strMap[null] = undefined; | ||
// All of these should be ok | ||
var num_ok1 = numMap[0]; | ||
var num_ok2 = numMap[0]; | ||
var num_ok3 = numMap[0]; | ||
var num_ok4 = numMap[NumericEnum1.A]; | ||
var num_ok5 = numMap[NumericEnum2.A]; | ||
// Generics | ||
function generic1(arg) { | ||
// Should error | ||
return arg["blah"]; | ||
} | ||
function generic2(arg) { | ||
// Should OK | ||
return arg["blah"]; | ||
} | ||
function generic3(arg) { | ||
// Should error | ||
return strMap[arg]; | ||
} | ||
obj1["x"]; | ||
var y = "y"; | ||
obj1[y]; | ||
var yy = "y"; | ||
obj1[yy]; | ||
var z = "z"; | ||
obj1[z]; | ||
// Should error | ||
var f1 = strMapUnion["foo"]; | ||
var e15 = symbolMap[s]; // Should OK | ||
symbolMap[s] = undefined; // Should error |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
None of these appear to be errors.