Skip to content

[release-4.6] Cherry pick #48941 (get narrowed type of symbol fix) #48943

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
376 changes: 376 additions & 0 deletions tests/baselines/reference/dependentDestructuredVariables.errors.txt
Original file line number Diff line number Diff line change
@@ -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<T> { variant: 'a', value: T }

interface B<T> { variant: 'b', value: Array<T> }

type AB<T> = A<T> | B<T>;

declare function printValue<T>(t: T): void;

declare function printValueList<T>(t: Array<T>): void;

function unrefined1<T>(ab: AB<T>): void {
const { variant, value } = ab;
if (variant === 'a') {
printValue<T>(value);
}
else {
printValueList<T>(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<number>;
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<any>;
}

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<any, any, any>;
}

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<any, any, any>;
~~~~~~~~~~~~~~
!!! 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 = <T extends ["a", number] | ["b", string]>(...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
}) {}

Loading