Skip to content

Commit

Permalink
Add a failing test case when the discriminant is a property of a para…
Browse files Browse the repository at this point in the history
…meter
  • Loading branch information
Andarist committed Dec 25, 2021
1 parent 35f7909 commit 44d9f91
Show file tree
Hide file tree
Showing 5 changed files with 372 additions and 0 deletions.
245 changes: 245 additions & 0 deletions tests/baselines/reference/dependentDestructuredVariables.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts(236,17): error TS2531: Object is possibly 'null'.


==== tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts (1 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] });

type XStateActionArgs =
| [event: { type: "LOG_OUT" }, context: { user: { name: string } }]
| [event: { type: "LOG_IN" }, context: { user: null }];
const xstateAction: (...args: XStateActionArgs) => void = (
event,
context
) => {
if (event.type === 'LOG_OUT') {
console.log(context.user.name)
~~~~~~~~~~~~
!!! error TS2531: Object is possibly 'null'.
}
};

29 changes: 29 additions & 0 deletions tests/baselines/reference/dependentDestructuredVariables.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,18 @@ const reducer: (...args: ReducerArgs) => void = (op, args) => {

reducer("add", { a: 1, b: 3 });
reducer("concat", { firstArr: [1, 2], secondArr: [3, 4] });

type XStateActionArgs =
| [event: { type: "LOG_OUT" }, context: { user: { name: string } }]
| [event: { type: "LOG_IN" }, context: { user: null }];
const xstateAction: (...args: XStateActionArgs) => void = (
event,
context
) => {
if (event.type === 'LOG_OUT') {
console.log(context.user.name)
}
};


//// [dependentDestructuredVariables.js]
Expand Down Expand Up @@ -394,6 +406,11 @@ const reducer = (op, args) => {
};
reducer("add", { a: 1, b: 3 });
reducer("concat", { firstArr: [1, 2], secondArr: [3, 4] });
const xstateAction = (event, context) => {
if (event.type === 'LOG_OUT') {
console.log(context.user.name);
}
};


//// [dependentDestructuredVariables.d.ts]
Expand Down Expand Up @@ -469,3 +486,15 @@ declare type ReducerArgs = ["add", {
secondArr: any[];
}];
declare const reducer: (...args: ReducerArgs) => void;
declare type XStateActionArgs = [event: {
type: "LOG_OUT";
}, context: {
user: {
name: string;
};
}] | [event: {
type: "LOG_IN";
}, context: {
user: null;
}];
declare const xstateAction: (...args: XStateActionArgs) => void;
41 changes: 41 additions & 0 deletions tests/baselines/reference/dependentDestructuredVariables.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -595,3 +595,44 @@ reducer("concat", { firstArr: [1, 2], secondArr: [3, 4] });
>firstArr : Symbol(firstArr, Decl(dependentDestructuredVariables.ts, 225, 19))
>secondArr : Symbol(secondArr, Decl(dependentDestructuredVariables.ts, 225, 37))

type XStateActionArgs =
>XStateActionArgs : Symbol(XStateActionArgs, Decl(dependentDestructuredVariables.ts, 225, 59))

| [event: { type: "LOG_OUT" }, context: { user: { name: string } }]
>type : Symbol(type, Decl(dependentDestructuredVariables.ts, 228, 13))
>user : Symbol(user, Decl(dependentDestructuredVariables.ts, 228, 43))
>name : Symbol(name, Decl(dependentDestructuredVariables.ts, 228, 51))

| [event: { type: "LOG_IN" }, context: { user: null }];
>type : Symbol(type, Decl(dependentDestructuredVariables.ts, 229, 13))
>user : Symbol(user, Decl(dependentDestructuredVariables.ts, 229, 42))

const xstateAction: (...args: XStateActionArgs) => void = (
>xstateAction : Symbol(xstateAction, Decl(dependentDestructuredVariables.ts, 230, 5))
>args : Symbol(args, Decl(dependentDestructuredVariables.ts, 230, 21))
>XStateActionArgs : Symbol(XStateActionArgs, Decl(dependentDestructuredVariables.ts, 225, 59))

event,
>event : Symbol(event, Decl(dependentDestructuredVariables.ts, 230, 59))

context
>context : Symbol(context, Decl(dependentDestructuredVariables.ts, 231, 8))

) => {
if (event.type === 'LOG_OUT') {
>event.type : Symbol(type, Decl(dependentDestructuredVariables.ts, 228, 13), Decl(dependentDestructuredVariables.ts, 229, 13))
>event : Symbol(event, Decl(dependentDestructuredVariables.ts, 230, 59))
>type : Symbol(type, Decl(dependentDestructuredVariables.ts, 228, 13), Decl(dependentDestructuredVariables.ts, 229, 13))

console.log(context.user.name)
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>context.user.name : Symbol(name, Decl(dependentDestructuredVariables.ts, 228, 51))
>context.user : Symbol(user, Decl(dependentDestructuredVariables.ts, 228, 43), Decl(dependentDestructuredVariables.ts, 229, 42))
>context : Symbol(context, Decl(dependentDestructuredVariables.ts, 231, 8))
>user : Symbol(user, Decl(dependentDestructuredVariables.ts, 228, 43), Decl(dependentDestructuredVariables.ts, 229, 42))
>name : Symbol(name, Decl(dependentDestructuredVariables.ts, 228, 51))
}
};

45 changes: 45 additions & 0 deletions tests/baselines/reference/dependentDestructuredVariables.types
Original file line number Diff line number Diff line change
Expand Up @@ -677,3 +677,48 @@ reducer("concat", { firstArr: [1, 2], secondArr: [3, 4] });
>3 : 3
>4 : 4

type XStateActionArgs =
>XStateActionArgs : XStateActionArgs

| [event: { type: "LOG_OUT" }, context: { user: { name: string } }]
>type : "LOG_OUT"
>user : { name: string; }
>name : string

| [event: { type: "LOG_IN" }, context: { user: null }];
>type : "LOG_IN"
>user : null
>null : null

const xstateAction: (...args: XStateActionArgs) => void = (
>xstateAction : (...args: XStateActionArgs) => void
>args : XStateActionArgs
>( event, context) => { if (event.type === 'LOG_OUT') { console.log(context.user.name) }} : (event: { type: "LOG_OUT"; } | { type: "LOG_IN"; }, context: { user: { name: string; }; } | { user: null; }) => void

event,
>event : { type: "LOG_OUT"; } | { type: "LOG_IN"; }

context
>context : { user: { name: string; }; } | { user: null; }

) => {
if (event.type === 'LOG_OUT') {
>event.type === 'LOG_OUT' : boolean
>event.type : "LOG_OUT" | "LOG_IN"
>event : { type: "LOG_OUT"; } | { type: "LOG_IN"; }
>type : "LOG_OUT" | "LOG_IN"
>'LOG_OUT' : "LOG_OUT"

console.log(context.user.name)
>console.log(context.user.name) : void
>console.log : (...data: any[]) => void
>console : Console
>log : (...data: any[]) => void
>context.user.name : string
>context.user : { name: string; } | null
>context : { user: { name: string; }; } | { user: null; }
>user : { name: string; } | null
>name : string
}
};

Loading

0 comments on commit 44d9f91

Please sign in to comment.