diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5a1f6f440fe7e..67fea0acf5442 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -25528,7 +25528,7 @@ namespace ts { if (isBindingElement(declaration) && !declaration.initializer && !declaration.dotDotDotToken && declaration.parent.elements.length >= 2) { const parent = declaration.parent.parent; if (parent.kind === SyntaxKind.VariableDeclaration && getCombinedNodeFlags(declaration) & NodeFlags.Const || parent.kind === SyntaxKind.Parameter) { - const links = getNodeLinks(location); + const links = getNodeLinks(parent); if (!(links.flags & NodeCheckFlags.InCheckIdentifier)) { links.flags |= NodeCheckFlags.InCheckIdentifier; const parentType = getTypeForBindingElementParent(parent, CheckMode.Normal); diff --git a/tests/baselines/reference/dependentDestructuredVariables.errors.txt b/tests/baselines/reference/dependentDestructuredVariables.errors.txt new file mode 100644 index 0000000000000..fbddf80744cc8 --- /dev/null +++ b/tests/baselines/reference/dependentDestructuredVariables.errors.txt @@ -0,0 +1,334 @@ +tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts(314,5): error TS7022: 'value1' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer. +tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts(314,5): error TS7031: Binding element 'value1' implicitly has an 'any' type. + + +==== tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts (2 errors) ==== + type Action = + | { kind: 'A', payload: number } + | { kind: 'B', payload: string }; + + function f10({ kind, payload }: Action) { + if (kind === 'A') { + payload.toFixed(); + } + if (kind === 'B') { + payload.toUpperCase(); + } + } + + function f11(action: Action) { + const { kind, payload } = action; + if (kind === 'A') { + payload.toFixed(); + } + if (kind === 'B') { + payload.toUpperCase(); + } + } + + function f12({ kind, payload }: Action) { + switch (kind) { + case 'A': + payload.toFixed(); + break; + case 'B': + payload.toUpperCase(); + break; + default: + payload; // never + } + } + + type Action2 = + | { kind: 'A', payload: number | undefined } + | { kind: 'B', payload: string | undefined }; + + function f20({ kind, payload }: Action2) { + if (payload) { + if (kind === 'A') { + payload.toFixed(); + } + if (kind === 'B') { + payload.toUpperCase(); + } + } + } + + function f21(action: Action2) { + const { kind, payload } = action; + if (payload) { + if (kind === 'A') { + payload.toFixed(); + } + if (kind === 'B') { + payload.toUpperCase(); + } + } + } + + function f22(action: Action2) { + if (action.payload) { + const { kind, payload } = action; + if (kind === 'A') { + payload.toFixed(); + } + if (kind === 'B') { + payload.toUpperCase(); + } + } + } + + function f23({ kind, payload }: Action2) { + if (payload) { + switch (kind) { + case 'A': + payload.toFixed(); + break; + case 'B': + payload.toUpperCase(); + break; + default: + payload; // never + } + } + } + + type Foo = + | { kind: 'A', isA: true } + | { kind: 'B', isA: false } + | { kind: 'C', isA: false }; + + function f30({ kind, isA }: Foo) { + if (kind === 'A') { + isA; // true + } + if (kind === 'B') { + isA; // false + } + if (kind === 'C') { + isA; // false + } + if (isA) { + kind; // 'A' + } + else { + kind; // 'B' | 'C' + } + } + + type Args = ['A', number] | ['B', string] + + function f40(...[kind, data]: Args) { + if (kind === 'A') { + data.toFixed(); + } + if (kind === 'B') { + data.toUpperCase(); + } + } + + // Repro from #35283 + + interface A { variant: 'a', value: T } + + interface B { variant: 'b', value: Array } + + type AB = A | B; + + declare function printValue(t: T): void; + + declare function printValueList(t: Array): void; + + function unrefined1(ab: AB): void { + const { variant, value } = ab; + if (variant === 'a') { + printValue(value); + } + else { + printValueList(value); + } + } + + // Repro from #38020 + + type Action3 = + | {type: 'add', payload: { toAdd: number } } + | {type: 'remove', payload: { toRemove: number } }; + + const reducerBroken = (state: number, { type, payload }: Action3) => { + switch (type) { + case 'add': + return state + payload.toAdd; + case 'remove': + return state - payload.toRemove; + } + } + + // Repro from #46143 + + declare var it: Iterator; + const { value, done } = it.next(); + if (!done) { + value; // number + } + + // Repro from #46658 + + declare function f50(cb: (...args: Args) => void): void + + f50((kind, data) => { + if (kind === 'A') { + data.toFixed(); + } + if (kind === 'B') { + data.toUpperCase(); + } + }); + + const f51: (...args: ['A', number] | ['B', string]) => void = (kind, payload) => { + if (kind === 'A') { + payload.toFixed(); + } + if (kind === 'B') { + payload.toUpperCase(); + } + }; + + const f52: (...args: ['A', number] | ['B']) => void = (kind, payload?) => { + if (kind === 'A') { + payload.toFixed(); + } + else { + payload; // undefined + } + }; + + declare function readFile(path: string, callback: (...args: [err: null, data: unknown[]] | [err: Error, data: undefined]) => void): void; + + readFile('hello', (err, data) => { + if (err === null) { + data.length; + } + else { + err.message; + } + }); + + type ReducerArgs = ["add", { a: number, b: number }] | ["concat", { firstArr: any[], secondArr: any[] }]; + + const reducer: (...args: ReducerArgs) => void = (op, args) => { + switch (op) { + case "add": + console.log(args.a + args.b); + break; + case "concat": + console.log(args.firstArr.concat(args.secondArr)); + break; + } + } + + reducer("add", { a: 1, b: 3 }); + reducer("concat", { firstArr: [1, 2], secondArr: [3, 4] }); + + // repro from https://github.com/microsoft/TypeScript/pull/47190#issuecomment-1057603588 + + type FooMethod = { + method(...args: + [type: "str", cb: (e: string) => void] | + [type: "num", cb: (e: number) => void] + ): void; + } + + let fooM: FooMethod = { + method(type, cb) { + if (type == 'num') { + cb(123) + } else { + cb("abc") + } + } + }; + + type FooAsyncMethod = { + method(...args: + [type: "str", cb: (e: string) => void] | + [type: "num", cb: (e: number) => void] + ): Promise; + } + + let fooAsyncM: FooAsyncMethod = { + async method(type, cb) { + if (type == 'num') { + cb(123) + } else { + cb("abc") + } + } + }; + + type FooGenMethod = { + method(...args: + [type: "str", cb: (e: string) => void] | + [type: "num", cb: (e: number) => void] + ): Generator; + } + + let fooGenM: FooGenMethod = { + *method(type, cb) { + if (type == 'num') { + cb(123) + } else { + cb("abc") + } + } + }; + + type FooAsyncGenMethod = { + method(...args: + [type: "str", cb: (e: string) => void] | + [type: "num", cb: (e: number) => void] + ): AsyncGenerator; + } + + let fooAsyncGenM: FooAsyncGenMethod = { + async *method(type, cb) { + if (type == 'num') { + cb(123) + } else { + cb("abc") + } + } + }; + + // Repro from #48345 + + type Func = (...args: T) => void; + + const f60: Func = (kind, payload) => { + if (kind === "a") { + payload.toFixed(); // error + } + if (kind === "b") { + payload.toUpperCase(); // error + } + }; + + // Repro from #48902 + + function foo({ + value1, + ~~~~~~ +!!! error TS7022: 'value1' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer. + ~~~~~~ +!!! error TS7031: Binding element 'value1' implicitly has an 'any' type. + test1 = value1.test1, + test2 = value1.test2, + test3 = value1.test3, + test4 = value1.test4, + test5 = value1.test5, + test6 = value1.test6, + test7 = value1.test7, + test8 = value1.test8, + test9 = value1.test9 + }) {} + \ No newline at end of file diff --git a/tests/baselines/reference/dependentDestructuredVariables.js b/tests/baselines/reference/dependentDestructuredVariables.js index a9f2006ec1e7a..eab12767faf7a 100644 --- a/tests/baselines/reference/dependentDestructuredVariables.js +++ b/tests/baselines/reference/dependentDestructuredVariables.js @@ -308,6 +308,21 @@ const f60: Func = (kind, payload) => { payload.toUpperCase(); // error } }; + +// Repro from #48902 + +function foo({ + value1, + test1 = value1.test1, + test2 = value1.test2, + test3 = value1.test3, + test4 = value1.test4, + test5 = value1.test5, + test6 = value1.test6, + test7 = value1.test7, + test8 = value1.test8, + test9 = value1.test9 +}) {} //// [dependentDestructuredVariables.js] @@ -550,6 +565,8 @@ const f60 = (kind, payload) => { payload.toUpperCase(); // error } }; +// Repro from #48902 +function foo({ value1, test1 = value1.test1, test2 = value1.test2, test3 = value1.test3, test4 = value1.test4, test5 = value1.test5, test6 = value1.test6, test7 = value1.test7, test8 = value1.test8, test9 = value1.test9 }) { } //// [dependentDestructuredVariables.d.ts] @@ -667,3 +684,15 @@ declare type FooAsyncGenMethod = { declare let fooAsyncGenM: FooAsyncGenMethod; declare type Func = (...args: T) => void; declare const f60: Func; +declare function foo({ value1, test1, test2, test3, test4, test5, test6, test7, test8, test9 }: { + value1: any; + test1?: any; + test2?: any; + test3?: any; + test4?: any; + test5?: any; + test6?: any; + test7?: any; + test8?: any; + test9?: any; +}): void; diff --git a/tests/baselines/reference/dependentDestructuredVariables.symbols b/tests/baselines/reference/dependentDestructuredVariables.symbols index f859b5ee7566f..ccaaaa72fe9d0 100644 --- a/tests/baselines/reference/dependentDestructuredVariables.symbols +++ b/tests/baselines/reference/dependentDestructuredVariables.symbols @@ -784,3 +784,49 @@ const f60: Func = (kind, payload) => { } }; +// Repro from #48902 + +function foo({ +>foo : Symbol(foo, Decl(dependentDestructuredVariables.ts, 308, 2)) + + value1, +>value1 : Symbol(value1, Decl(dependentDestructuredVariables.ts, 312, 14)) + + test1 = value1.test1, +>test1 : Symbol(test1, Decl(dependentDestructuredVariables.ts, 313, 11)) +>value1 : Symbol(value1, Decl(dependentDestructuredVariables.ts, 312, 14)) + + test2 = value1.test2, +>test2 : Symbol(test2, Decl(dependentDestructuredVariables.ts, 314, 25)) +>value1 : Symbol(value1, Decl(dependentDestructuredVariables.ts, 312, 14)) + + test3 = value1.test3, +>test3 : Symbol(test3, Decl(dependentDestructuredVariables.ts, 315, 25)) +>value1 : Symbol(value1, Decl(dependentDestructuredVariables.ts, 312, 14)) + + test4 = value1.test4, +>test4 : Symbol(test4, Decl(dependentDestructuredVariables.ts, 316, 25)) +>value1 : Symbol(value1, Decl(dependentDestructuredVariables.ts, 312, 14)) + + test5 = value1.test5, +>test5 : Symbol(test5, Decl(dependentDestructuredVariables.ts, 317, 25)) +>value1 : Symbol(value1, Decl(dependentDestructuredVariables.ts, 312, 14)) + + test6 = value1.test6, +>test6 : Symbol(test6, Decl(dependentDestructuredVariables.ts, 318, 25)) +>value1 : Symbol(value1, Decl(dependentDestructuredVariables.ts, 312, 14)) + + test7 = value1.test7, +>test7 : Symbol(test7, Decl(dependentDestructuredVariables.ts, 319, 25)) +>value1 : Symbol(value1, Decl(dependentDestructuredVariables.ts, 312, 14)) + + test8 = value1.test8, +>test8 : Symbol(test8, Decl(dependentDestructuredVariables.ts, 320, 25)) +>value1 : Symbol(value1, Decl(dependentDestructuredVariables.ts, 312, 14)) + + test9 = value1.test9 +>test9 : Symbol(test9, Decl(dependentDestructuredVariables.ts, 321, 25)) +>value1 : Symbol(value1, Decl(dependentDestructuredVariables.ts, 312, 14)) + +}) {} + diff --git a/tests/baselines/reference/dependentDestructuredVariables.types b/tests/baselines/reference/dependentDestructuredVariables.types index 440c42a38277d..f3f9024231324 100644 --- a/tests/baselines/reference/dependentDestructuredVariables.types +++ b/tests/baselines/reference/dependentDestructuredVariables.types @@ -891,3 +891,67 @@ const f60: Func = (kind, payload) => { } }; +// Repro from #48902 + +function foo({ +>foo : ({ value1, test1, test2, test3, test4, test5, test6, test7, test8, test9 }: { value1: any; test1?: any; test2?: any; test3?: any; test4?: any; test5?: any; test6?: any; test7?: any; test8?: any; test9?: any; }) => void + + value1, +>value1 : any + + test1 = value1.test1, +>test1 : any +>value1.test1 : any +>value1 : any +>test1 : any + + test2 = value1.test2, +>test2 : any +>value1.test2 : any +>value1 : any +>test2 : any + + test3 = value1.test3, +>test3 : any +>value1.test3 : any +>value1 : any +>test3 : any + + test4 = value1.test4, +>test4 : any +>value1.test4 : any +>value1 : any +>test4 : any + + test5 = value1.test5, +>test5 : any +>value1.test5 : any +>value1 : any +>test5 : any + + test6 = value1.test6, +>test6 : any +>value1.test6 : any +>value1 : any +>test6 : any + + test7 = value1.test7, +>test7 : any +>value1.test7 : any +>value1 : any +>test7 : any + + test8 = value1.test8, +>test8 : any +>value1.test8 : any +>value1 : any +>test8 : any + + test9 = value1.test9 +>test9 : any +>value1.test9 : any +>value1 : any +>test9 : any + +}) {} + diff --git a/tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts b/tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts index b56045e7ec061..ae11c010fadb9 100644 --- a/tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts +++ b/tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts @@ -312,3 +312,18 @@ const f60: Func = (kind, payload) => { payload.toUpperCase(); // error } }; + +// Repro from #48902 + +function foo({ + value1, + test1 = value1.test1, + test2 = value1.test2, + test3 = value1.test3, + test4 = value1.test4, + test5 = value1.test5, + test6 = value1.test6, + test7 = value1.test7, + test8 = value1.test8, + test9 = value1.test9 +}) {}