diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 40d626fa0dddf..6033d00c7ff34 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -25119,7 +25119,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..63fbacd6997bc --- /dev/null +++ b/tests/baselines/reference/dependentDestructuredVariables.errors.txt @@ -0,0 +1,376 @@ +error TS2318: Cannot find global type 'AsyncIterableIterator'. +tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts(240,10): error TS2345: Argument of type 'number' is not assignable to parameter of type 'never'. +tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts(242,10): error TS2345: Argument of type 'string' is not assignable to parameter of type 'never'. +tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts(257,10): error TS2345: Argument of type 'number' is not assignable to parameter of type 'never'. +tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts(259,10): error TS2345: Argument of type 'string' is not assignable to parameter of type 'never'. +tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts(274,10): error TS2345: Argument of type 'number' is not assignable to parameter of type 'never'. +tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts(276,10): error TS2345: Argument of type 'string' is not assignable to parameter of type 'never'. +tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts(285,6): error TS2583: Cannot find name 'AsyncGenerator'. Do you need to change your target library? Try changing the 'lib' compiler option to 'es2018' or later. +tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts(285,6): error TS4057: Return type of method from exported interface has or is using private name 'AsyncGenerator'. +tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts(291,10): error TS2345: Argument of type 'number' is not assignable to parameter of type 'never'. +tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts(293,10): error TS2345: Argument of type 'string' is not assignable to parameter of type 'never'. +tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts(304,17): error TS2339: Property 'toFixed' does not exist on type 'string | number'. + Property 'toFixed' does not exist on type 'string'. +tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts(307,17): error TS2339: Property 'toUpperCase' does not exist on type 'string | number'. + Property 'toUpperCase' does not exist on type 'number'. +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. + + +!!! error TS2318: Cannot find global type 'AsyncIterableIterator'. +==== tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts (14 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) + ~~~ +!!! error TS2345: Argument of type 'number' is not assignable to parameter of type 'never'. + } else { + cb("abc") + ~~~~~ +!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'never'. + } + } + }; + + 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) + ~~~ +!!! error TS2345: Argument of type 'number' is not assignable to parameter of type 'never'. + } else { + cb("abc") + ~~~~~ +!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'never'. + } + } + }; + + 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) + ~~~ +!!! error TS2345: Argument of type 'number' is not assignable to parameter of type 'never'. + } else { + cb("abc") + ~~~~~ +!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'never'. + } + } + }; + + type FooAsyncGenMethod = { + method(...args: + [type: "str", cb: (e: string) => void] | + [type: "num", cb: (e: number) => void] + ): AsyncGenerator; + ~~~~~~~~~~~~~~ +!!! error TS2583: Cannot find name 'AsyncGenerator'. Do you need to change your target library? Try changing the 'lib' compiler option to 'es2018' or later. + ~~~~~~~~~~~~~~ +!!! error TS4057: Return type of method from exported interface has or is using private name 'AsyncGenerator'. + } + + let fooAsyncGenM: FooAsyncGenMethod = { + async *method(type, cb) { + if (type == 'num') { + cb(123) + ~~~ +!!! error TS2345: Argument of type 'number' is not assignable to parameter of type 'never'. + } else { + cb("abc") + ~~~~~ +!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'never'. + } + } + }; + + // Repro from #48345 + + type Func = (...args: T) => void; + + const f60: Func = (kind, payload) => { + if (kind === "a") { + payload.toFixed(); // error + ~~~~~~~ +!!! error TS2339: Property 'toFixed' does not exist on type 'string | number'. +!!! error TS2339: Property 'toFixed' does not exist on type 'string'. + } + if (kind === "b") { + payload.toUpperCase(); // error + ~~~~~~~~~~~ +!!! error TS2339: Property 'toUpperCase' does not exist on type 'string | number'. +!!! error TS2339: Property 'toUpperCase' does not exist on type 'number'. + } + }; + + // 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 2eb7be3d946a4..6fd8ada37ce87 100644 --- a/tests/baselines/reference/dependentDestructuredVariables.js +++ b/tests/baselines/reference/dependentDestructuredVariables.js @@ -225,10 +225,129 @@ const reducer: (...args: ReducerArgs) => void = (op, args) => { 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, + 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] "use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); } +var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var g = generator.apply(thisArg, _arguments || []), i, q = []; + return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i; + function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; } + function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } + function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } + function fulfill(value) { resume("next", value); } + function reject(value) { resume("throw", value); } + function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } +}; function f10({ kind, payload }) { if (kind === 'A') { payload.toFixed(); @@ -394,78 +513,57 @@ const reducer = (op, args) => { }; reducer("add", { a: 1, b: 3 }); reducer("concat", { firstArr: [1, 2], secondArr: [3, 4] }); - - -//// [dependentDestructuredVariables.d.ts] -declare type Action = { - kind: 'A'; - payload: number; -} | { - kind: 'B'; - payload: string; +let fooM = { + method(type, cb) { + if (type == 'num') { + cb(123); + } + else { + cb("abc"); + } + } }; -declare function f10({ kind, payload }: Action): void; -declare function f11(action: Action): void; -declare function f12({ kind, payload }: Action): void; -declare type Action2 = { - kind: 'A'; - payload: number | undefined; -} | { - kind: 'B'; - payload: string | undefined; +let fooAsyncM = { + method(type, cb) { + return __awaiter(this, void 0, void 0, function* () { + if (type == 'num') { + cb(123); + } + else { + cb("abc"); + } + }); + } }; -declare function f20({ kind, payload }: Action2): void; -declare function f21(action: Action2): void; -declare function f22(action: Action2): void; -declare function f23({ kind, payload }: Action2): void; -declare type Foo = { - kind: 'A'; - isA: true; -} | { - kind: 'B'; - isA: false; -} | { - kind: 'C'; - isA: false; +let fooGenM = { + *method(type, cb) { + if (type == 'num') { + cb(123); + } + else { + cb("abc"); + } + } }; -declare function f30({ kind, isA }: Foo): void; -declare type Args = ['A', number] | ['B', string]; -declare function f40(...[kind, data]: Args): void; -interface A { - variant: 'a'; - value: T; -} -interface B { - variant: 'b'; - value: Array; -} -declare type AB = A | B; -declare function printValue(t: T): void; -declare function printValueList(t: Array): void; -declare function unrefined1(ab: AB): void; -declare type Action3 = { - type: 'add'; - payload: { - toAdd: number; - }; -} | { - type: 'remove'; - payload: { - toRemove: number; - }; +let fooAsyncGenM = { + method(type, cb) { + return __asyncGenerator(this, arguments, function* method_1() { + if (type == 'num') { + cb(123); + } + else { + cb("abc"); + } + }); + } +}; +const f60 = (kind, payload) => { + if (kind === "a") { + payload.toFixed(); // error + } + if (kind === "b") { + payload.toUpperCase(); // error + } }; -declare const reducerBroken: (state: number, { type, payload }: Action3) => number; -declare var it: Iterator; -declare const value: any, done: boolean | undefined; -declare function f50(cb: (...args: Args) => void): void; -declare const f51: (...args: ['A', number] | ['B', string]) => void; -declare const f52: (...args: ['A', number] | ['B']) => void; -declare function readFile(path: string, callback: (...args: [err: null, data: unknown[]] | [err: Error, data: undefined]) => void): void; -declare type ReducerArgs = ["add", { - a: number; - b: number; -}] | ["concat", { - firstArr: any[]; - secondArr: any[]; -}]; -declare const reducer: (...args: ReducerArgs) => void; +// 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 }) { } diff --git a/tests/baselines/reference/dependentDestructuredVariables.symbols b/tests/baselines/reference/dependentDestructuredVariables.symbols index bad7fbf5b690e..e82305b550862 100644 --- a/tests/baselines/reference/dependentDestructuredVariables.symbols +++ b/tests/baselines/reference/dependentDestructuredVariables.symbols @@ -595,3 +595,234 @@ reducer("concat", { firstArr: [1, 2], secondArr: [3, 4] }); >firstArr : Symbol(firstArr, Decl(dependentDestructuredVariables.ts, 225, 19)) >secondArr : Symbol(secondArr, Decl(dependentDestructuredVariables.ts, 225, 37)) +// repro from https://github.com/microsoft/TypeScript/pull/47190#issuecomment-1057603588 + +type FooMethod = { +>FooMethod : Symbol(FooMethod, Decl(dependentDestructuredVariables.ts, 225, 59)) + + method(...args: +>method : Symbol(method, Decl(dependentDestructuredVariables.ts, 229, 18)) +>args : Symbol(args, Decl(dependentDestructuredVariables.ts, 230, 9)) + + [type: "str", cb: (e: string) => void] | +>e : Symbol(e, Decl(dependentDestructuredVariables.ts, 231, 23)) + + [type: "num", cb: (e: number) => void] +>e : Symbol(e, Decl(dependentDestructuredVariables.ts, 232, 23)) + + ): void; +} + +let fooM: FooMethod = { +>fooM : Symbol(fooM, Decl(dependentDestructuredVariables.ts, 236, 3)) +>FooMethod : Symbol(FooMethod, Decl(dependentDestructuredVariables.ts, 225, 59)) + + method(type, cb) { +>method : Symbol(method, Decl(dependentDestructuredVariables.ts, 236, 23)) +>type : Symbol(type, Decl(dependentDestructuredVariables.ts, 237, 9)) +>cb : Symbol(cb, Decl(dependentDestructuredVariables.ts, 237, 14)) + + if (type == 'num') { +>type : Symbol(type, Decl(dependentDestructuredVariables.ts, 237, 9)) + + cb(123) +>cb : Symbol(cb, Decl(dependentDestructuredVariables.ts, 237, 14)) + + } else { + cb("abc") +>cb : Symbol(cb, Decl(dependentDestructuredVariables.ts, 237, 14)) + } + } +}; + +type FooAsyncMethod = { +>FooAsyncMethod : Symbol(FooAsyncMethod, Decl(dependentDestructuredVariables.ts, 244, 2)) + + method(...args: +>method : Symbol(method, Decl(dependentDestructuredVariables.ts, 246, 23)) +>args : Symbol(args, Decl(dependentDestructuredVariables.ts, 247, 9)) + + [type: "str", cb: (e: string) => void] | +>e : Symbol(e, Decl(dependentDestructuredVariables.ts, 248, 23)) + + [type: "num", cb: (e: number) => void] +>e : Symbol(e, Decl(dependentDestructuredVariables.ts, 249, 23)) + + ): Promise; +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) +} + +let fooAsyncM: FooAsyncMethod = { +>fooAsyncM : Symbol(fooAsyncM, Decl(dependentDestructuredVariables.ts, 253, 3)) +>FooAsyncMethod : Symbol(FooAsyncMethod, Decl(dependentDestructuredVariables.ts, 244, 2)) + + async method(type, cb) { +>method : Symbol(method, Decl(dependentDestructuredVariables.ts, 253, 33)) +>type : Symbol(type, Decl(dependentDestructuredVariables.ts, 254, 15)) +>cb : Symbol(cb, Decl(dependentDestructuredVariables.ts, 254, 20)) + + if (type == 'num') { +>type : Symbol(type, Decl(dependentDestructuredVariables.ts, 254, 15)) + + cb(123) +>cb : Symbol(cb, Decl(dependentDestructuredVariables.ts, 254, 20)) + + } else { + cb("abc") +>cb : Symbol(cb, Decl(dependentDestructuredVariables.ts, 254, 20)) + } + } +}; + +type FooGenMethod = { +>FooGenMethod : Symbol(FooGenMethod, Decl(dependentDestructuredVariables.ts, 261, 2)) + + method(...args: +>method : Symbol(method, Decl(dependentDestructuredVariables.ts, 263, 21)) +>args : Symbol(args, Decl(dependentDestructuredVariables.ts, 264, 9)) + + [type: "str", cb: (e: string) => void] | +>e : Symbol(e, Decl(dependentDestructuredVariables.ts, 265, 23)) + + [type: "num", cb: (e: number) => void] +>e : Symbol(e, Decl(dependentDestructuredVariables.ts, 266, 23)) + + ): Generator; +>Generator : Symbol(Generator, Decl(lib.es2015.generator.d.ts, --, --)) +} + +let fooGenM: FooGenMethod = { +>fooGenM : Symbol(fooGenM, Decl(dependentDestructuredVariables.ts, 270, 3)) +>FooGenMethod : Symbol(FooGenMethod, Decl(dependentDestructuredVariables.ts, 261, 2)) + + *method(type, cb) { +>method : Symbol(method, Decl(dependentDestructuredVariables.ts, 270, 29)) +>type : Symbol(type, Decl(dependentDestructuredVariables.ts, 271, 10)) +>cb : Symbol(cb, Decl(dependentDestructuredVariables.ts, 271, 15)) + + if (type == 'num') { +>type : Symbol(type, Decl(dependentDestructuredVariables.ts, 271, 10)) + + cb(123) +>cb : Symbol(cb, Decl(dependentDestructuredVariables.ts, 271, 15)) + + } else { + cb("abc") +>cb : Symbol(cb, Decl(dependentDestructuredVariables.ts, 271, 15)) + } + } +}; + +type FooAsyncGenMethod = { +>FooAsyncGenMethod : Symbol(FooAsyncGenMethod, Decl(dependentDestructuredVariables.ts, 278, 2)) + + method(...args: +>method : Symbol(method, Decl(dependentDestructuredVariables.ts, 280, 26)) +>args : Symbol(args, Decl(dependentDestructuredVariables.ts, 281, 9)) + + [type: "str", cb: (e: string) => void] | +>e : Symbol(e, Decl(dependentDestructuredVariables.ts, 282, 23)) + + [type: "num", cb: (e: number) => void] +>e : Symbol(e, Decl(dependentDestructuredVariables.ts, 283, 23)) + + ): AsyncGenerator; +>AsyncGenerator : Symbol(AsyncGenerator) +} + +let fooAsyncGenM: FooAsyncGenMethod = { +>fooAsyncGenM : Symbol(fooAsyncGenM, Decl(dependentDestructuredVariables.ts, 287, 3)) +>FooAsyncGenMethod : Symbol(FooAsyncGenMethod, Decl(dependentDestructuredVariables.ts, 278, 2)) + + async *method(type, cb) { +>method : Symbol(method, Decl(dependentDestructuredVariables.ts, 287, 39)) +>type : Symbol(type, Decl(dependentDestructuredVariables.ts, 288, 16)) +>cb : Symbol(cb, Decl(dependentDestructuredVariables.ts, 288, 21)) + + if (type == 'num') { +>type : Symbol(type, Decl(dependentDestructuredVariables.ts, 288, 16)) + + cb(123) +>cb : Symbol(cb, Decl(dependentDestructuredVariables.ts, 288, 21)) + + } else { + cb("abc") +>cb : Symbol(cb, Decl(dependentDestructuredVariables.ts, 288, 21)) + } + } +}; + +// Repro from #48345 + +type Func = (...args: T) => void; +>Func : Symbol(Func, Decl(dependentDestructuredVariables.ts, 295, 2)) +>T : Symbol(T, Decl(dependentDestructuredVariables.ts, 299, 13)) +>args : Symbol(args, Decl(dependentDestructuredVariables.ts, 299, 54)) +>T : Symbol(T, Decl(dependentDestructuredVariables.ts, 299, 13)) + +const f60: Func = (kind, payload) => { +>f60 : Symbol(f60, Decl(dependentDestructuredVariables.ts, 301, 5)) +>Func : Symbol(Func, Decl(dependentDestructuredVariables.ts, 295, 2)) +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 301, 19)) +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 301, 24)) + + if (kind === "a") { +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 301, 19)) + + payload.toFixed(); // error +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 301, 24)) + } + if (kind === "b") { +>kind : Symbol(kind, Decl(dependentDestructuredVariables.ts, 301, 19)) + + payload.toUpperCase(); // error +>payload : Symbol(payload, Decl(dependentDestructuredVariables.ts, 301, 24)) + } +}; + +// 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 a1b16d186ee08..aebda192879e4 100644 --- a/tests/baselines/reference/dependentDestructuredVariables.types +++ b/tests/baselines/reference/dependentDestructuredVariables.types @@ -677,3 +677,281 @@ reducer("concat", { firstArr: [1, 2], secondArr: [3, 4] }); >3 : 3 >4 : 4 +// repro from https://github.com/microsoft/TypeScript/pull/47190#issuecomment-1057603588 + +type FooMethod = { +>FooMethod : FooMethod + + method(...args: +>method : (...args: [type: "str", cb: (e: string) => void] | [type: "num", cb: (e: number) => void]) => void +>args : [type: "str", cb: (e: string) => void] | [type: "num", cb: (e: number) => void] + + [type: "str", cb: (e: string) => void] | +>e : string + + [type: "num", cb: (e: number) => void] +>e : number + + ): void; +} + +let fooM: FooMethod = { +>fooM : FooMethod +>{ method(type, cb) { if (type == 'num') { cb(123) } else { cb("abc") } }} : { method(type: "str" | "num", cb: ((e: string) => void) | ((e: number) => void)): void; } + + method(type, cb) { +>method : (type: "str" | "num", cb: ((e: string) => void) | ((e: number) => void)) => void +>type : "str" | "num" +>cb : ((e: string) => void) | ((e: number) => void) + + if (type == 'num') { +>type == 'num' : boolean +>type : "str" | "num" +>'num' : "num" + + cb(123) +>cb(123) : void +>cb : ((e: string) => void) | ((e: number) => void) +>123 : 123 + + } else { + cb("abc") +>cb("abc") : void +>cb : ((e: string) => void) | ((e: number) => void) +>"abc" : "abc" + } + } +}; + +type FooAsyncMethod = { +>FooAsyncMethod : FooAsyncMethod + + method(...args: +>method : (...args: [type: "str", cb: (e: string) => void] | [type: "num", cb: (e: number) => void]) => Promise +>args : [type: "str", cb: (e: string) => void] | [type: "num", cb: (e: number) => void] + + [type: "str", cb: (e: string) => void] | +>e : string + + [type: "num", cb: (e: number) => void] +>e : number + + ): Promise; +} + +let fooAsyncM: FooAsyncMethod = { +>fooAsyncM : FooAsyncMethod +>{ async method(type, cb) { if (type == 'num') { cb(123) } else { cb("abc") } }} : { method(type: "str" | "num", cb: ((e: string) => void) | ((e: number) => void)): Promise; } + + async method(type, cb) { +>method : (type: "str" | "num", cb: ((e: string) => void) | ((e: number) => void)) => Promise +>type : "str" | "num" +>cb : ((e: string) => void) | ((e: number) => void) + + if (type == 'num') { +>type == 'num' : boolean +>type : "str" | "num" +>'num' : "num" + + cb(123) +>cb(123) : void +>cb : ((e: string) => void) | ((e: number) => void) +>123 : 123 + + } else { + cb("abc") +>cb("abc") : void +>cb : ((e: string) => void) | ((e: number) => void) +>"abc" : "abc" + } + } +}; + +type FooGenMethod = { +>FooGenMethod : FooGenMethod + + method(...args: +>method : (...args: [type: "str", cb: (e: string) => void] | [type: "num", cb: (e: number) => void]) => Generator +>args : [type: "str", cb: (e: string) => void] | [type: "num", cb: (e: number) => void] + + [type: "str", cb: (e: string) => void] | +>e : string + + [type: "num", cb: (e: number) => void] +>e : number + + ): Generator; +} + +let fooGenM: FooGenMethod = { +>fooGenM : FooGenMethod +>{ *method(type, cb) { if (type == 'num') { cb(123) } else { cb("abc") } }} : { method(type: "str" | "num", cb: ((e: string) => void) | ((e: number) => void)): Generator; } + + *method(type, cb) { +>method : (type: "str" | "num", cb: ((e: string) => void) | ((e: number) => void)) => Generator +>type : "str" | "num" +>cb : ((e: string) => void) | ((e: number) => void) + + if (type == 'num') { +>type == 'num' : boolean +>type : "str" | "num" +>'num' : "num" + + cb(123) +>cb(123) : void +>cb : ((e: string) => void) | ((e: number) => void) +>123 : 123 + + } else { + cb("abc") +>cb("abc") : void +>cb : ((e: string) => void) | ((e: number) => void) +>"abc" : "abc" + } + } +}; + +type FooAsyncGenMethod = { +>FooAsyncGenMethod : FooAsyncGenMethod + + method(...args: +>method : (...args: [type: "str", cb: (e: string) => void] | [type: "num", cb: (e: number) => void]) => AsyncGenerator +>args : [type: "str", cb: (e: string) => void] | [type: "num", cb: (e: number) => void] + + [type: "str", cb: (e: string) => void] | +>e : string + + [type: "num", cb: (e: number) => void] +>e : number + + ): AsyncGenerator; +} + +let fooAsyncGenM: FooAsyncGenMethod = { +>fooAsyncGenM : FooAsyncGenMethod +>{ async *method(type, cb) { if (type == 'num') { cb(123) } else { cb("abc") } }} : { method(type: "str" | "num", cb: ((e: string) => void) | ((e: number) => void)): {}; } + + async *method(type, cb) { +>method : (type: "str" | "num", cb: ((e: string) => void) | ((e: number) => void)) => {} +>type : "str" | "num" +>cb : ((e: string) => void) | ((e: number) => void) + + if (type == 'num') { +>type == 'num' : boolean +>type : "str" | "num" +>'num' : "num" + + cb(123) +>cb(123) : void +>cb : ((e: string) => void) | ((e: number) => void) +>123 : 123 + + } else { + cb("abc") +>cb("abc") : void +>cb : ((e: string) => void) | ((e: number) => void) +>"abc" : "abc" + } + } +}; + +// Repro from #48345 + +type Func = (...args: T) => void; +>Func : Func +>args : T + +const f60: Func = (kind, payload) => { +>f60 : Func +>(kind, payload) => { if (kind === "a") { payload.toFixed(); // error } if (kind === "b") { payload.toUpperCase(); // error }} : (kind: T[0], payload: T[1]) => void +>kind : T[0] +>payload : T[1] + + if (kind === "a") { +>kind === "a" : boolean +>kind : T[0] +>"a" : "a" + + payload.toFixed(); // error +>payload.toFixed() : any +>payload.toFixed : any +>payload : string | number +>toFixed : any + } + if (kind === "b") { +>kind === "b" : boolean +>kind : T[0] +>"b" : "b" + + payload.toUpperCase(); // error +>payload.toUpperCase() : any +>payload.toUpperCase : any +>payload : string | number +>toUpperCase : any + } +}; + +// 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 38bcb68d048e8..174f3d023155b 100644 --- a/tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts +++ b/tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts @@ -228,3 +228,101 @@ const reducer: (...args: ReducerArgs) => void = (op, args) => { 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, + 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 +}) {}