Skip to content

Commit 2c0c128

Browse files
authored
Avoid incorrect narrowings using const variables from binding elemens with literal initializers (microsoft#56347)
1 parent d845ee2 commit 2c0c128

4 files changed

+66
-1
lines changed

src/compiler/checker.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -26214,7 +26214,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2621426214
if (hasOnlyExpressionInitializer(declaration) && isBlockScopedNameDeclaredBeforeUse(declaration, node)) {
2621526215
const initializer = getEffectiveInitializer(declaration);
2621626216
if (initializer) {
26217-
return tryGetNameFromType(getTypeOfExpression(initializer));
26217+
const initializerType = isBindingPattern(declaration.parent) ? getTypeForBindingElement(declaration as BindingElement) : getTypeOfExpression(initializer);
26218+
return initializerType && tryGetNameFromType(initializerType);
2621826219
}
2621926220
if (isEnumMember(declaration)) {
2622026221
return getTextOfPropertyName(declaration.name);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//// [tests/cases/compiler/avoidNarrowingUsingConstVariableFromBindingElementWithLiteralInitializer.ts] ////
2+
3+
=== avoidNarrowingUsingConstVariableFromBindingElementWithLiteralInitializer.ts ===
4+
declare const foo: ["a", string, number] | ["b", string, boolean];
5+
>foo : Symbol(foo, Decl(avoidNarrowingUsingConstVariableFromBindingElementWithLiteralInitializer.ts, 0, 13))
6+
7+
export function test(arg: { index?: number }) {
8+
>test : Symbol(test, Decl(avoidNarrowingUsingConstVariableFromBindingElementWithLiteralInitializer.ts, 0, 66))
9+
>arg : Symbol(arg, Decl(avoidNarrowingUsingConstVariableFromBindingElementWithLiteralInitializer.ts, 2, 21))
10+
>index : Symbol(index, Decl(avoidNarrowingUsingConstVariableFromBindingElementWithLiteralInitializer.ts, 2, 27))
11+
12+
const { index = 0 } = arg;
13+
>index : Symbol(index, Decl(avoidNarrowingUsingConstVariableFromBindingElementWithLiteralInitializer.ts, 3, 9))
14+
>arg : Symbol(arg, Decl(avoidNarrowingUsingConstVariableFromBindingElementWithLiteralInitializer.ts, 2, 21))
15+
16+
if (foo[index] === "a") {
17+
>foo : Symbol(foo, Decl(avoidNarrowingUsingConstVariableFromBindingElementWithLiteralInitializer.ts, 0, 13))
18+
>index : Symbol(index, Decl(avoidNarrowingUsingConstVariableFromBindingElementWithLiteralInitializer.ts, 3, 9))
19+
20+
foo;
21+
>foo : Symbol(foo, Decl(avoidNarrowingUsingConstVariableFromBindingElementWithLiteralInitializer.ts, 0, 13))
22+
}
23+
}
24+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//// [tests/cases/compiler/avoidNarrowingUsingConstVariableFromBindingElementWithLiteralInitializer.ts] ////
2+
3+
=== avoidNarrowingUsingConstVariableFromBindingElementWithLiteralInitializer.ts ===
4+
declare const foo: ["a", string, number] | ["b", string, boolean];
5+
>foo : ["a", string, number] | ["b", string, boolean]
6+
7+
export function test(arg: { index?: number }) {
8+
>test : (arg: { index?: number | undefined; }) => void
9+
>arg : { index?: number | undefined; }
10+
>index : number | undefined
11+
12+
const { index = 0 } = arg;
13+
>index : number
14+
>0 : 0
15+
>arg : { index?: number | undefined; }
16+
17+
if (foo[index] === "a") {
18+
>foo[index] === "a" : boolean
19+
>foo[index] : string | number | boolean
20+
>foo : ["a", string, number] | ["b", string, boolean]
21+
>index : number
22+
>"a" : "a"
23+
24+
foo;
25+
>foo : ["a", string, number] | ["b", string, boolean]
26+
}
27+
}
28+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// @strict: true
2+
// @noEmit: true
3+
4+
declare const foo: ["a", string, number] | ["b", string, boolean];
5+
6+
export function test(arg: { index?: number }) {
7+
const { index = 0 } = arg;
8+
9+
if (foo[index] === "a") {
10+
foo;
11+
}
12+
}

0 commit comments

Comments
 (0)