diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 717652d1d1770..0670304eb96c0 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -22767,7 +22767,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return propType; } if (everyType(type, isTupleType)) { - return mapType(type, t => getRestTypeOfTupleType(t as TupleTypeReference) || undefinedType); + return mapType(type, t => { + const tupleType = t as TupleTypeReference; + const restType = getRestTypeOfTupleType(tupleType); + if (!restType) { + return undefinedType; + } + if (compilerOptions.noUncheckedIndexedAccess && + index >= tupleType.target.fixedLength + getEndElementCount(tupleType.target, ElementFlags.Fixed)) { + return getUnionType([restType, undefinedType]); + } + return restType; + }); } return undefined; } diff --git a/tests/baselines/reference/destructureTupleWithVariableElement.errors.txt b/tests/baselines/reference/destructureTupleWithVariableElement.errors.txt new file mode 100644 index 0000000000000..7d6e22c7f3d5e --- /dev/null +++ b/tests/baselines/reference/destructureTupleWithVariableElement.errors.txt @@ -0,0 +1,31 @@ +tests/cases/compiler/destructureTupleWithVariableElement.ts(9,1): error TS18048: 's1' is possibly 'undefined'. +tests/cases/compiler/destructureTupleWithVariableElement.ts(10,1): error TS18048: 's2' is possibly 'undefined'. +tests/cases/compiler/destructureTupleWithVariableElement.ts(18,1): error TS18048: 's5' is possibly 'undefined'. + + +==== tests/cases/compiler/destructureTupleWithVariableElement.ts (3 errors) ==== + // repro from #52302 + + type NonEmptyStringArray = [string, ...Array] + + const strings: NonEmptyStringArray = ['one', 'two'] + const [s0, s1, s2] = strings; + + s0.toUpperCase() + s1.toUpperCase() + ~~ +!!! error TS18048: 's1' is possibly 'undefined'. + s2.toUpperCase() + ~~ +!!! error TS18048: 's2' is possibly 'undefined'. + + declare const strings2: [string, ...Array, string] + + const [s3, s4, s5] = strings2; + + s3.toUpperCase() + s4.toUpperCase() + s5.toUpperCase() + ~~ +!!! error TS18048: 's5' is possibly 'undefined'. + \ No newline at end of file diff --git a/tests/baselines/reference/destructureTupleWithVariableElement.symbols b/tests/baselines/reference/destructureTupleWithVariableElement.symbols new file mode 100644 index 0000000000000..cb9582c0894c0 --- /dev/null +++ b/tests/baselines/reference/destructureTupleWithVariableElement.symbols @@ -0,0 +1,57 @@ +=== tests/cases/compiler/destructureTupleWithVariableElement.ts === +// repro from #52302 + +type NonEmptyStringArray = [string, ...Array] +>NonEmptyStringArray : Symbol(NonEmptyStringArray, Decl(destructureTupleWithVariableElement.ts, 0, 0)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + +const strings: NonEmptyStringArray = ['one', 'two'] +>strings : Symbol(strings, Decl(destructureTupleWithVariableElement.ts, 4, 5)) +>NonEmptyStringArray : Symbol(NonEmptyStringArray, Decl(destructureTupleWithVariableElement.ts, 0, 0)) + +const [s0, s1, s2] = strings; +>s0 : Symbol(s0, Decl(destructureTupleWithVariableElement.ts, 5, 7)) +>s1 : Symbol(s1, Decl(destructureTupleWithVariableElement.ts, 5, 10)) +>s2 : Symbol(s2, Decl(destructureTupleWithVariableElement.ts, 5, 14)) +>strings : Symbol(strings, Decl(destructureTupleWithVariableElement.ts, 4, 5)) + +s0.toUpperCase() +>s0.toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) +>s0 : Symbol(s0, Decl(destructureTupleWithVariableElement.ts, 5, 7)) +>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) + +s1.toUpperCase() +>s1.toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) +>s1 : Symbol(s1, Decl(destructureTupleWithVariableElement.ts, 5, 10)) +>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) + +s2.toUpperCase() +>s2.toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) +>s2 : Symbol(s2, Decl(destructureTupleWithVariableElement.ts, 5, 14)) +>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) + +declare const strings2: [string, ...Array, string] +>strings2 : Symbol(strings2, Decl(destructureTupleWithVariableElement.ts, 11, 13)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + +const [s3, s4, s5] = strings2; +>s3 : Symbol(s3, Decl(destructureTupleWithVariableElement.ts, 13, 7)) +>s4 : Symbol(s4, Decl(destructureTupleWithVariableElement.ts, 13, 10)) +>s5 : Symbol(s5, Decl(destructureTupleWithVariableElement.ts, 13, 14)) +>strings2 : Symbol(strings2, Decl(destructureTupleWithVariableElement.ts, 11, 13)) + +s3.toUpperCase() +>s3.toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) +>s3 : Symbol(s3, Decl(destructureTupleWithVariableElement.ts, 13, 7)) +>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) + +s4.toUpperCase() +>s4.toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) +>s4 : Symbol(s4, Decl(destructureTupleWithVariableElement.ts, 13, 10)) +>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) + +s5.toUpperCase() +>s5.toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) +>s5 : Symbol(s5, Decl(destructureTupleWithVariableElement.ts, 13, 14)) +>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) + diff --git a/tests/baselines/reference/destructureTupleWithVariableElement.types b/tests/baselines/reference/destructureTupleWithVariableElement.types new file mode 100644 index 0000000000000..1aec5823e2349 --- /dev/null +++ b/tests/baselines/reference/destructureTupleWithVariableElement.types @@ -0,0 +1,63 @@ +=== tests/cases/compiler/destructureTupleWithVariableElement.ts === +// repro from #52302 + +type NonEmptyStringArray = [string, ...Array] +>NonEmptyStringArray : [string, ...string[]] + +const strings: NonEmptyStringArray = ['one', 'two'] +>strings : [string, ...string[]] +>['one', 'two'] : [string, string] +>'one' : "one" +>'two' : "two" + +const [s0, s1, s2] = strings; +>s0 : string +>s1 : string | undefined +>s2 : string | undefined +>strings : [string, ...string[]] + +s0.toUpperCase() +>s0.toUpperCase() : string +>s0.toUpperCase : () => string +>s0 : string +>toUpperCase : () => string + +s1.toUpperCase() +>s1.toUpperCase() : string +>s1.toUpperCase : () => string +>s1 : string | undefined +>toUpperCase : () => string + +s2.toUpperCase() +>s2.toUpperCase() : string +>s2.toUpperCase : () => string +>s2 : string | undefined +>toUpperCase : () => string + +declare const strings2: [string, ...Array, string] +>strings2 : [string, ...string[], string] + +const [s3, s4, s5] = strings2; +>s3 : string +>s4 : string | undefined +>s5 : string | undefined +>strings2 : [string, ...string[], string] + +s3.toUpperCase() +>s3.toUpperCase() : string +>s3.toUpperCase : () => string +>s3 : string +>toUpperCase : () => string + +s4.toUpperCase() +>s4.toUpperCase() : string +>s4.toUpperCase : () => string +>s4 : string +>toUpperCase : () => string + +s5.toUpperCase() +>s5.toUpperCase() : string +>s5.toUpperCase : () => string +>s5 : string | undefined +>toUpperCase : () => string + diff --git a/tests/cases/compiler/destructureTupleWithVariableElement.ts b/tests/cases/compiler/destructureTupleWithVariableElement.ts new file mode 100644 index 0000000000000..44e58afe0fdf2 --- /dev/null +++ b/tests/cases/compiler/destructureTupleWithVariableElement.ts @@ -0,0 +1,22 @@ +// @strict: true +// @noUncheckedIndexedAccess: true +// @noEmit: true + +// repro from #52302 + +type NonEmptyStringArray = [string, ...Array] + +const strings: NonEmptyStringArray = ['one', 'two'] +const [s0, s1, s2] = strings; + +s0.toUpperCase() +s1.toUpperCase() +s2.toUpperCase() + +declare const strings2: [string, ...Array, string] + +const [s3, s4, s5] = strings2; + +s3.toUpperCase() +s4.toUpperCase() +s5.toUpperCase()