From d0547f1d0b06e3fff1c4eff75830462b3749aaee Mon Sep 17 00:00:00 2001 From: navya9singh Date: Thu, 14 Jul 2022 14:43:46 -0700 Subject: [PATCH] noUncheckedIndexedAccess with enums Type narrowed --- src/compiler/checker.ts | 5 ++ .../reference/noUncheckedIndexAccess.js | 37 +++++++++++ .../reference/noUncheckedIndexAccess.symbols | 60 +++++++++++++++++ .../reference/noUncheckedIndexAccess.types | 65 +++++++++++++++++++ .../cases/compiler/noUncheckedIndexAccess.ts | 21 ++++++ 5 files changed, 188 insertions(+) create mode 100644 tests/baselines/reference/noUncheckedIndexAccess.js create mode 100644 tests/baselines/reference/noUncheckedIndexAccess.symbols create mode 100644 tests/baselines/reference/noUncheckedIndexAccess.types create mode 100644 tests/cases/compiler/noUncheckedIndexAccess.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index de3c34e0679a3..c89299ce6b1b8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15589,6 +15589,11 @@ m2: ${(this.mapper2 as unknown as DebugTypeMapper).__debugToString().split("\n") return accessFlags & AccessFlags.IncludeUndefined ? getUnionType([indexInfo.type, undefinedType]) : indexInfo.type; } errorIfWritingToReadonlyIndex(indexInfo); + if (accessFlags & AccessFlags.IncludeUndefined && objectType.symbol.flags & (SymbolFlags.RegularEnum | SymbolFlags.ConstEnum)) { + if(indexType.flags & TypeFlags.EnumLiteral){ + return indexInfo.type; + } + } return accessFlags & AccessFlags.IncludeUndefined ? getUnionType([indexInfo.type, undefinedType]) : indexInfo.type; } if (indexType.flags & TypeFlags.Never) { diff --git a/tests/baselines/reference/noUncheckedIndexAccess.js b/tests/baselines/reference/noUncheckedIndexAccess.js new file mode 100644 index 0000000000000..3b1e3839e1ce8 --- /dev/null +++ b/tests/baselines/reference/noUncheckedIndexAccess.js @@ -0,0 +1,37 @@ +//// [noUncheckedIndexAccess.ts] +enum Meat { + Sausage, + Bacon + } + const sausage = Meat.Sausage + const valueSausage = Meat[sausage] + + const bacon = Meat.Bacon + const valueBacon = Meat[bacon] + + const union: Meat.Bacon | Meat.Sausage = Meat.Bacon + const valueUnion = Meat[union] + + //Avoiding a false positive + const value = Meat[0] + + const t = "testing" + const value2 = Meat[t] + + +//// [noUncheckedIndexAccess.js] +var Meat; +(function (Meat) { + Meat[Meat["Sausage"] = 0] = "Sausage"; + Meat[Meat["Bacon"] = 1] = "Bacon"; +})(Meat || (Meat = {})); +var sausage = Meat.Sausage; +var valueSausage = Meat[sausage]; +var bacon = Meat.Bacon; +var valueBacon = Meat[bacon]; +var union = Meat.Bacon; +var valueUnion = Meat[union]; +//Avoiding a false positive +var value = Meat[0]; +var t = "testing"; +var value2 = Meat[t]; diff --git a/tests/baselines/reference/noUncheckedIndexAccess.symbols b/tests/baselines/reference/noUncheckedIndexAccess.symbols new file mode 100644 index 0000000000000..2f6c8a570610d --- /dev/null +++ b/tests/baselines/reference/noUncheckedIndexAccess.symbols @@ -0,0 +1,60 @@ +=== tests/cases/compiler/noUncheckedIndexAccess.ts === +enum Meat { +>Meat : Symbol(Meat, Decl(noUncheckedIndexAccess.ts, 0, 0)) + + Sausage, +>Sausage : Symbol(Meat.Sausage, Decl(noUncheckedIndexAccess.ts, 0, 11)) + + Bacon +>Bacon : Symbol(Meat.Bacon, Decl(noUncheckedIndexAccess.ts, 1, 12)) + } + const sausage = Meat.Sausage +>sausage : Symbol(sausage, Decl(noUncheckedIndexAccess.ts, 4, 7)) +>Meat.Sausage : Symbol(Meat.Sausage, Decl(noUncheckedIndexAccess.ts, 0, 11)) +>Meat : Symbol(Meat, Decl(noUncheckedIndexAccess.ts, 0, 0)) +>Sausage : Symbol(Meat.Sausage, Decl(noUncheckedIndexAccess.ts, 0, 11)) + + const valueSausage = Meat[sausage] +>valueSausage : Symbol(valueSausage, Decl(noUncheckedIndexAccess.ts, 5, 7)) +>Meat : Symbol(Meat, Decl(noUncheckedIndexAccess.ts, 0, 0)) +>sausage : Symbol(sausage, Decl(noUncheckedIndexAccess.ts, 4, 7)) + + const bacon = Meat.Bacon +>bacon : Symbol(bacon, Decl(noUncheckedIndexAccess.ts, 7, 7)) +>Meat.Bacon : Symbol(Meat.Bacon, Decl(noUncheckedIndexAccess.ts, 1, 12)) +>Meat : Symbol(Meat, Decl(noUncheckedIndexAccess.ts, 0, 0)) +>Bacon : Symbol(Meat.Bacon, Decl(noUncheckedIndexAccess.ts, 1, 12)) + + const valueBacon = Meat[bacon] +>valueBacon : Symbol(valueBacon, Decl(noUncheckedIndexAccess.ts, 8, 7)) +>Meat : Symbol(Meat, Decl(noUncheckedIndexAccess.ts, 0, 0)) +>bacon : Symbol(bacon, Decl(noUncheckedIndexAccess.ts, 7, 7)) + + const union: Meat.Bacon | Meat.Sausage = Meat.Bacon +>union : Symbol(union, Decl(noUncheckedIndexAccess.ts, 10, 7)) +>Meat : Symbol(Meat, Decl(noUncheckedIndexAccess.ts, 0, 0)) +>Bacon : Symbol(Meat.Bacon, Decl(noUncheckedIndexAccess.ts, 1, 12)) +>Meat : Symbol(Meat, Decl(noUncheckedIndexAccess.ts, 0, 0)) +>Sausage : Symbol(Meat.Sausage, Decl(noUncheckedIndexAccess.ts, 0, 11)) +>Meat.Bacon : Symbol(Meat.Bacon, Decl(noUncheckedIndexAccess.ts, 1, 12)) +>Meat : Symbol(Meat, Decl(noUncheckedIndexAccess.ts, 0, 0)) +>Bacon : Symbol(Meat.Bacon, Decl(noUncheckedIndexAccess.ts, 1, 12)) + + const valueUnion = Meat[union] +>valueUnion : Symbol(valueUnion, Decl(noUncheckedIndexAccess.ts, 11, 7)) +>Meat : Symbol(Meat, Decl(noUncheckedIndexAccess.ts, 0, 0)) +>union : Symbol(union, Decl(noUncheckedIndexAccess.ts, 10, 7)) + + //Avoiding a false positive + const value = Meat[0] +>value : Symbol(value, Decl(noUncheckedIndexAccess.ts, 14, 7)) +>Meat : Symbol(Meat, Decl(noUncheckedIndexAccess.ts, 0, 0)) + + const t = "testing" +>t : Symbol(t, Decl(noUncheckedIndexAccess.ts, 16, 7)) + + const value2 = Meat[t] +>value2 : Symbol(value2, Decl(noUncheckedIndexAccess.ts, 17, 7)) +>Meat : Symbol(Meat, Decl(noUncheckedIndexAccess.ts, 0, 0)) +>t : Symbol(t, Decl(noUncheckedIndexAccess.ts, 16, 7)) + diff --git a/tests/baselines/reference/noUncheckedIndexAccess.types b/tests/baselines/reference/noUncheckedIndexAccess.types new file mode 100644 index 0000000000000..3eab3e64bed3d --- /dev/null +++ b/tests/baselines/reference/noUncheckedIndexAccess.types @@ -0,0 +1,65 @@ +=== tests/cases/compiler/noUncheckedIndexAccess.ts === +enum Meat { +>Meat : Meat + + Sausage, +>Sausage : Meat.Sausage + + Bacon +>Bacon : Meat.Bacon + } + const sausage = Meat.Sausage +>sausage : Meat.Sausage +>Meat.Sausage : Meat.Sausage +>Meat : typeof Meat +>Sausage : Meat.Sausage + + const valueSausage = Meat[sausage] +>valueSausage : string +>Meat[sausage] : string +>Meat : typeof Meat +>sausage : Meat.Sausage + + const bacon = Meat.Bacon +>bacon : Meat.Bacon +>Meat.Bacon : Meat.Bacon +>Meat : typeof Meat +>Bacon : Meat.Bacon + + const valueBacon = Meat[bacon] +>valueBacon : string +>Meat[bacon] : string +>Meat : typeof Meat +>bacon : Meat.Bacon + + const union: Meat.Bacon | Meat.Sausage = Meat.Bacon +>union : Meat +>Meat : any +>Meat : any +>Meat.Bacon : Meat.Bacon +>Meat : typeof Meat +>Bacon : Meat.Bacon + + const valueUnion = Meat[union] +>valueUnion : string +>Meat[union] : string +>Meat : typeof Meat +>union : Meat.Bacon + + //Avoiding a false positive + const value = Meat[0] +>value : string | undefined +>Meat[0] : string | undefined +>Meat : typeof Meat +>0 : 0 + + const t = "testing" +>t : "testing" +>"testing" : "testing" + + const value2 = Meat[t] +>value2 : error +>Meat[t] : error +>Meat : typeof Meat +>t : "testing" + diff --git a/tests/cases/compiler/noUncheckedIndexAccess.ts b/tests/cases/compiler/noUncheckedIndexAccess.ts new file mode 100644 index 0000000000000..0891d9e40ae4b --- /dev/null +++ b/tests/cases/compiler/noUncheckedIndexAccess.ts @@ -0,0 +1,21 @@ +//@noUncheckedIndexedAccess: true +//@strictNullChecks: true + +enum Meat { + Sausage, + Bacon + } + const sausage = Meat.Sausage + const valueSausage = Meat[sausage] + + const bacon = Meat.Bacon + const valueBacon = Meat[bacon] + + const union: Meat.Bacon | Meat.Sausage = Meat.Bacon + const valueUnion = Meat[union] + + //Avoiding a false positive + const value = Meat[0] + + const t = "testing" + const value2 = Meat[t]