From 14c65b311959501b6720ff48b9cb02eecbcee4a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 2 Dec 2024 21:12:58 +0100 Subject: [PATCH] Check if switch statements are exhaustive when their expressions is generic with a literal type constraint (#60644) --- src/compiler/checker.ts | 2 +- .../reference/dependentReturnType9.errors.txt | 71 ++++ .../reference/dependentReturnType9.symbols | 173 ++++++++++ .../reference/dependentReturnType9.types | 306 ++++++++++++++++++ tests/cases/compiler/dependentReturnType9.ts | 67 ++++ 5 files changed, 618 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/dependentReturnType9.errors.txt create mode 100644 tests/baselines/reference/dependentReturnType9.symbols create mode 100644 tests/baselines/reference/dependentReturnType9.types create mode 100644 tests/cases/compiler/dependentReturnType9.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3d3f908d82c79..397a424ee7b27 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -38682,7 +38682,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // A missing not-equal flag indicates that the type wasn't handled by some case. return !someType(operandConstraint, t => getTypeFacts(t, notEqualFacts) === notEqualFacts); } - const type = checkExpressionCached(node.expression); + const type = getBaseConstraintOrType(checkExpressionCached(node.expression)); if (!isLiteralType(type)) { return false; } diff --git a/tests/baselines/reference/dependentReturnType9.errors.txt b/tests/baselines/reference/dependentReturnType9.errors.txt new file mode 100644 index 0000000000000..da12eeaab2eb4 --- /dev/null +++ b/tests/baselines/reference/dependentReturnType9.errors.txt @@ -0,0 +1,71 @@ +dependentReturnType9.ts(57,4): error TS2366: Function lacks ending return statement and return type does not include 'undefined'. + + +==== dependentReturnType9.ts (1 errors) ==== + type Payload = + | { _tag: "auth"; username: string; password: string } + | { _tag: "cart"; items: Array<{ id: string; quantity: number }> } + | { _tag: "person"; name: string; age: number }; + + type PayloadContent = { + [P in Payload as P["_tag"]]: Omit; + }; + + // ok, exhaustive cases and default case with throw + function mockPayload( + str: P_TAG, + ): PayloadContent[P_TAG] { + switch (str) { + case "auth": + return { username: "test", password: "admin" }; + case "cart": + return { items: [{ id: "123", quantity: 123 }] }; + case "person": + return { name: "andrea", age: 27 }; + default: + throw new Error("unknown tag"); + } + } + + // ok, non-exhaustive cases but default case with throw + function mockPayload2( + str: P_TAG, + ): PayloadContent[P_TAG] { + switch (str) { + case "auth": + return { username: "test", password: "admin" }; + case "cart": + return { items: [{ id: "123", quantity: 123 }] }; + default: + throw new Error("unhandled tag"); + } + } + + // ok, exhaustive cases + function mockPayload3( + str: P_TAG, + ): PayloadContent[P_TAG] { + switch (str) { + case "auth": + return { username: "test", password: "admin" }; + case "cart": + return { items: [{ id: "123", quantity: 123 }] }; + case "person": + return { name: "andrea", age: 27 }; + } + } + + // error, non-exhaustive cases + function mockPayload4( + str: P_TAG, + ): PayloadContent[P_TAG] { + ~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2366: Function lacks ending return statement and return type does not include 'undefined'. + switch (str) { + case "auth": + return { username: "test", password: "admin" }; + case "cart": + return { items: [{ id: "123", quantity: 123 }] }; + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/dependentReturnType9.symbols b/tests/baselines/reference/dependentReturnType9.symbols new file mode 100644 index 0000000000000..d66bb2d76f040 --- /dev/null +++ b/tests/baselines/reference/dependentReturnType9.symbols @@ -0,0 +1,173 @@ +//// [tests/cases/compiler/dependentReturnType9.ts] //// + +=== dependentReturnType9.ts === +type Payload = +>Payload : Symbol(Payload, Decl(dependentReturnType9.ts, 0, 0)) + + | { _tag: "auth"; username: string; password: string } +>_tag : Symbol(_tag, Decl(dependentReturnType9.ts, 1, 5)) +>username : Symbol(username, Decl(dependentReturnType9.ts, 1, 19)) +>password : Symbol(password, Decl(dependentReturnType9.ts, 1, 37)) + + | { _tag: "cart"; items: Array<{ id: string; quantity: number }> } +>_tag : Symbol(_tag, Decl(dependentReturnType9.ts, 2, 5)) +>items : Symbol(items, Decl(dependentReturnType9.ts, 2, 19)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>id : Symbol(id, Decl(dependentReturnType9.ts, 2, 34)) +>quantity : Symbol(quantity, Decl(dependentReturnType9.ts, 2, 46)) + + | { _tag: "person"; name: string; age: number }; +>_tag : Symbol(_tag, Decl(dependentReturnType9.ts, 3, 5)) +>name : Symbol(name, Decl(dependentReturnType9.ts, 3, 21)) +>age : Symbol(age, Decl(dependentReturnType9.ts, 3, 35)) + +type PayloadContent = { +>PayloadContent : Symbol(PayloadContent, Decl(dependentReturnType9.ts, 3, 50)) + + [P in Payload as P["_tag"]]: Omit; +>P : Symbol(P, Decl(dependentReturnType9.ts, 6, 3)) +>Payload : Symbol(Payload, Decl(dependentReturnType9.ts, 0, 0)) +>P : Symbol(P, Decl(dependentReturnType9.ts, 6, 3)) +>Omit : Symbol(Omit, Decl(lib.es5.d.ts, --, --)) +>P : Symbol(P, Decl(dependentReturnType9.ts, 6, 3)) + +}; + +// ok, exhaustive cases and default case with throw +function mockPayload( +>mockPayload : Symbol(mockPayload, Decl(dependentReturnType9.ts, 7, 2)) +>P_TAG : Symbol(P_TAG, Decl(dependentReturnType9.ts, 10, 21)) +>Payload : Symbol(Payload, Decl(dependentReturnType9.ts, 0, 0)) + + str: P_TAG, +>str : Symbol(str, Decl(dependentReturnType9.ts, 10, 52)) +>P_TAG : Symbol(P_TAG, Decl(dependentReturnType9.ts, 10, 21)) + +): PayloadContent[P_TAG] { +>PayloadContent : Symbol(PayloadContent, Decl(dependentReturnType9.ts, 3, 50)) +>P_TAG : Symbol(P_TAG, Decl(dependentReturnType9.ts, 10, 21)) + + switch (str) { +>str : Symbol(str, Decl(dependentReturnType9.ts, 10, 52)) + + case "auth": + return { username: "test", password: "admin" }; +>username : Symbol(username, Decl(dependentReturnType9.ts, 15, 14)) +>password : Symbol(password, Decl(dependentReturnType9.ts, 15, 32)) + + case "cart": + return { items: [{ id: "123", quantity: 123 }] }; +>items : Symbol(items, Decl(dependentReturnType9.ts, 17, 14)) +>id : Symbol(id, Decl(dependentReturnType9.ts, 17, 24)) +>quantity : Symbol(quantity, Decl(dependentReturnType9.ts, 17, 35)) + + case "person": + return { name: "andrea", age: 27 }; +>name : Symbol(name, Decl(dependentReturnType9.ts, 19, 14)) +>age : Symbol(age, Decl(dependentReturnType9.ts, 19, 30)) + + default: + throw new Error("unknown tag"); +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + } +} + +// ok, non-exhaustive cases but default case with throw +function mockPayload2( +>mockPayload2 : Symbol(mockPayload2, Decl(dependentReturnType9.ts, 23, 1)) +>P_TAG : Symbol(P_TAG, Decl(dependentReturnType9.ts, 26, 22)) +>Payload : Symbol(Payload, Decl(dependentReturnType9.ts, 0, 0)) + + str: P_TAG, +>str : Symbol(str, Decl(dependentReturnType9.ts, 26, 53)) +>P_TAG : Symbol(P_TAG, Decl(dependentReturnType9.ts, 26, 22)) + +): PayloadContent[P_TAG] { +>PayloadContent : Symbol(PayloadContent, Decl(dependentReturnType9.ts, 3, 50)) +>P_TAG : Symbol(P_TAG, Decl(dependentReturnType9.ts, 26, 22)) + + switch (str) { +>str : Symbol(str, Decl(dependentReturnType9.ts, 26, 53)) + + case "auth": + return { username: "test", password: "admin" }; +>username : Symbol(username, Decl(dependentReturnType9.ts, 31, 14)) +>password : Symbol(password, Decl(dependentReturnType9.ts, 31, 32)) + + case "cart": + return { items: [{ id: "123", quantity: 123 }] }; +>items : Symbol(items, Decl(dependentReturnType9.ts, 33, 14)) +>id : Symbol(id, Decl(dependentReturnType9.ts, 33, 24)) +>quantity : Symbol(quantity, Decl(dependentReturnType9.ts, 33, 35)) + + default: + throw new Error("unhandled tag"); +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + } +} + +// ok, exhaustive cases +function mockPayload3( +>mockPayload3 : Symbol(mockPayload3, Decl(dependentReturnType9.ts, 37, 1)) +>P_TAG : Symbol(P_TAG, Decl(dependentReturnType9.ts, 40, 22)) +>Payload : Symbol(Payload, Decl(dependentReturnType9.ts, 0, 0)) + + str: P_TAG, +>str : Symbol(str, Decl(dependentReturnType9.ts, 40, 53)) +>P_TAG : Symbol(P_TAG, Decl(dependentReturnType9.ts, 40, 22)) + +): PayloadContent[P_TAG] { +>PayloadContent : Symbol(PayloadContent, Decl(dependentReturnType9.ts, 3, 50)) +>P_TAG : Symbol(P_TAG, Decl(dependentReturnType9.ts, 40, 22)) + + switch (str) { +>str : Symbol(str, Decl(dependentReturnType9.ts, 40, 53)) + + case "auth": + return { username: "test", password: "admin" }; +>username : Symbol(username, Decl(dependentReturnType9.ts, 45, 14)) +>password : Symbol(password, Decl(dependentReturnType9.ts, 45, 32)) + + case "cart": + return { items: [{ id: "123", quantity: 123 }] }; +>items : Symbol(items, Decl(dependentReturnType9.ts, 47, 14)) +>id : Symbol(id, Decl(dependentReturnType9.ts, 47, 24)) +>quantity : Symbol(quantity, Decl(dependentReturnType9.ts, 47, 35)) + + case "person": + return { name: "andrea", age: 27 }; +>name : Symbol(name, Decl(dependentReturnType9.ts, 49, 14)) +>age : Symbol(age, Decl(dependentReturnType9.ts, 49, 30)) + } +} + +// error, non-exhaustive cases +function mockPayload4( +>mockPayload4 : Symbol(mockPayload4, Decl(dependentReturnType9.ts, 51, 1)) +>P_TAG : Symbol(P_TAG, Decl(dependentReturnType9.ts, 54, 22)) +>Payload : Symbol(Payload, Decl(dependentReturnType9.ts, 0, 0)) + + str: P_TAG, +>str : Symbol(str, Decl(dependentReturnType9.ts, 54, 53)) +>P_TAG : Symbol(P_TAG, Decl(dependentReturnType9.ts, 54, 22)) + +): PayloadContent[P_TAG] { +>PayloadContent : Symbol(PayloadContent, Decl(dependentReturnType9.ts, 3, 50)) +>P_TAG : Symbol(P_TAG, Decl(dependentReturnType9.ts, 54, 22)) + + switch (str) { +>str : Symbol(str, Decl(dependentReturnType9.ts, 54, 53)) + + case "auth": + return { username: "test", password: "admin" }; +>username : Symbol(username, Decl(dependentReturnType9.ts, 59, 14)) +>password : Symbol(password, Decl(dependentReturnType9.ts, 59, 32)) + + case "cart": + return { items: [{ id: "123", quantity: 123 }] }; +>items : Symbol(items, Decl(dependentReturnType9.ts, 61, 14)) +>id : Symbol(id, Decl(dependentReturnType9.ts, 61, 24)) +>quantity : Symbol(quantity, Decl(dependentReturnType9.ts, 61, 35)) + } +} + diff --git a/tests/baselines/reference/dependentReturnType9.types b/tests/baselines/reference/dependentReturnType9.types new file mode 100644 index 0000000000000..834e5f578388b --- /dev/null +++ b/tests/baselines/reference/dependentReturnType9.types @@ -0,0 +1,306 @@ +//// [tests/cases/compiler/dependentReturnType9.ts] //// + +=== dependentReturnType9.ts === +type Payload = +>Payload : Payload +> : ^^^^^^^ + + | { _tag: "auth"; username: string; password: string } +>_tag : "auth" +> : ^^^^^^ +>username : string +> : ^^^^^^ +>password : string +> : ^^^^^^ + + | { _tag: "cart"; items: Array<{ id: string; quantity: number }> } +>_tag : "cart" +> : ^^^^^^ +>items : { id: string; quantity: number; }[] +> : ^^^^^^ ^^^^^^^^^^^^ ^^^^^ +>id : string +> : ^^^^^^ +>quantity : number +> : ^^^^^^ + + | { _tag: "person"; name: string; age: number }; +>_tag : "person" +> : ^^^^^^^^ +>name : string +> : ^^^^^^ +>age : number +> : ^^^^^^ + +type PayloadContent = { +>PayloadContent : PayloadContent +> : ^^^^^^^^^^^^^^ + + [P in Payload as P["_tag"]]: Omit; +}; + +// ok, exhaustive cases and default case with throw +function mockPayload( +>mockPayload : (str: P_TAG) => PayloadContent[P_TAG] +> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ + + str: P_TAG, +>str : P_TAG +> : ^^^^^ + +): PayloadContent[P_TAG] { + switch (str) { +>str : P_TAG +> : ^^^^^ + + case "auth": +>"auth" : "auth" +> : ^^^^^^ + + return { username: "test", password: "admin" }; +>{ username: "test", password: "admin" } : { username: string; password: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>username : string +> : ^^^^^^ +>"test" : "test" +> : ^^^^^^ +>password : string +> : ^^^^^^ +>"admin" : "admin" +> : ^^^^^^^ + + case "cart": +>"cart" : "cart" +> : ^^^^^^ + + return { items: [{ id: "123", quantity: 123 }] }; +>{ items: [{ id: "123", quantity: 123 }] } : { items: { id: string; quantity: number; }[]; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>items : { id: string; quantity: number; }[] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>[{ id: "123", quantity: 123 }] : { id: string; quantity: number; }[] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ id: "123", quantity: 123 } : { id: string; quantity: number; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>id : string +> : ^^^^^^ +>"123" : "123" +> : ^^^^^ +>quantity : number +> : ^^^^^^ +>123 : 123 +> : ^^^ + + case "person": +>"person" : "person" +> : ^^^^^^^^ + + return { name: "andrea", age: 27 }; +>{ name: "andrea", age: 27 } : { name: string; age: number; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>name : string +> : ^^^^^^ +>"andrea" : "andrea" +> : ^^^^^^^^ +>age : number +> : ^^^^^^ +>27 : 27 +> : ^^ + + default: + throw new Error("unknown tag"); +>new Error("unknown tag") : Error +> : ^^^^^ +>Error : ErrorConstructor +> : ^^^^^^^^^^^^^^^^ +>"unknown tag" : "unknown tag" +> : ^^^^^^^^^^^^^ + } +} + +// ok, non-exhaustive cases but default case with throw +function mockPayload2( +>mockPayload2 : (str: P_TAG) => PayloadContent[P_TAG] +> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ + + str: P_TAG, +>str : P_TAG +> : ^^^^^ + +): PayloadContent[P_TAG] { + switch (str) { +>str : P_TAG +> : ^^^^^ + + case "auth": +>"auth" : "auth" +> : ^^^^^^ + + return { username: "test", password: "admin" }; +>{ username: "test", password: "admin" } : { username: string; password: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>username : string +> : ^^^^^^ +>"test" : "test" +> : ^^^^^^ +>password : string +> : ^^^^^^ +>"admin" : "admin" +> : ^^^^^^^ + + case "cart": +>"cart" : "cart" +> : ^^^^^^ + + return { items: [{ id: "123", quantity: 123 }] }; +>{ items: [{ id: "123", quantity: 123 }] } : { items: { id: string; quantity: number; }[]; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>items : { id: string; quantity: number; }[] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>[{ id: "123", quantity: 123 }] : { id: string; quantity: number; }[] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ id: "123", quantity: 123 } : { id: string; quantity: number; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>id : string +> : ^^^^^^ +>"123" : "123" +> : ^^^^^ +>quantity : number +> : ^^^^^^ +>123 : 123 +> : ^^^ + + default: + throw new Error("unhandled tag"); +>new Error("unhandled tag") : Error +> : ^^^^^ +>Error : ErrorConstructor +> : ^^^^^^^^^^^^^^^^ +>"unhandled tag" : "unhandled tag" +> : ^^^^^^^^^^^^^^^ + } +} + +// ok, exhaustive cases +function mockPayload3( +>mockPayload3 : (str: P_TAG) => PayloadContent[P_TAG] +> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ + + str: P_TAG, +>str : P_TAG +> : ^^^^^ + +): PayloadContent[P_TAG] { + switch (str) { +>str : P_TAG +> : ^^^^^ + + case "auth": +>"auth" : "auth" +> : ^^^^^^ + + return { username: "test", password: "admin" }; +>{ username: "test", password: "admin" } : { username: string; password: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>username : string +> : ^^^^^^ +>"test" : "test" +> : ^^^^^^ +>password : string +> : ^^^^^^ +>"admin" : "admin" +> : ^^^^^^^ + + case "cart": +>"cart" : "cart" +> : ^^^^^^ + + return { items: [{ id: "123", quantity: 123 }] }; +>{ items: [{ id: "123", quantity: 123 }] } : { items: { id: string; quantity: number; }[]; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>items : { id: string; quantity: number; }[] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>[{ id: "123", quantity: 123 }] : { id: string; quantity: number; }[] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ id: "123", quantity: 123 } : { id: string; quantity: number; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>id : string +> : ^^^^^^ +>"123" : "123" +> : ^^^^^ +>quantity : number +> : ^^^^^^ +>123 : 123 +> : ^^^ + + case "person": +>"person" : "person" +> : ^^^^^^^^ + + return { name: "andrea", age: 27 }; +>{ name: "andrea", age: 27 } : { name: string; age: number; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>name : string +> : ^^^^^^ +>"andrea" : "andrea" +> : ^^^^^^^^ +>age : number +> : ^^^^^^ +>27 : 27 +> : ^^ + } +} + +// error, non-exhaustive cases +function mockPayload4( +>mockPayload4 : (str: P_TAG) => PayloadContent[P_TAG] +> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ + + str: P_TAG, +>str : P_TAG +> : ^^^^^ + +): PayloadContent[P_TAG] { + switch (str) { +>str : P_TAG +> : ^^^^^ + + case "auth": +>"auth" : "auth" +> : ^^^^^^ + + return { username: "test", password: "admin" }; +>{ username: "test", password: "admin" } : { username: string; password: string; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>username : string +> : ^^^^^^ +>"test" : "test" +> : ^^^^^^ +>password : string +> : ^^^^^^ +>"admin" : "admin" +> : ^^^^^^^ + + case "cart": +>"cart" : "cart" +> : ^^^^^^ + + return { items: [{ id: "123", quantity: 123 }] }; +>{ items: [{ id: "123", quantity: 123 }] } : { items: { id: string; quantity: number; }[]; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>items : { id: string; quantity: number; }[] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>[{ id: "123", quantity: 123 }] : { id: string; quantity: number; }[] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ id: "123", quantity: 123 } : { id: string; quantity: number; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>id : string +> : ^^^^^^ +>"123" : "123" +> : ^^^^^ +>quantity : number +> : ^^^^^^ +>123 : 123 +> : ^^^ + } +} + diff --git a/tests/cases/compiler/dependentReturnType9.ts b/tests/cases/compiler/dependentReturnType9.ts new file mode 100644 index 0000000000000..65437a8aea1c8 --- /dev/null +++ b/tests/cases/compiler/dependentReturnType9.ts @@ -0,0 +1,67 @@ +// @strict: true +// @noEmit: true + +type Payload = + | { _tag: "auth"; username: string; password: string } + | { _tag: "cart"; items: Array<{ id: string; quantity: number }> } + | { _tag: "person"; name: string; age: number }; + +type PayloadContent = { + [P in Payload as P["_tag"]]: Omit; +}; + +// ok, exhaustive cases and default case with throw +function mockPayload( + str: P_TAG, +): PayloadContent[P_TAG] { + switch (str) { + case "auth": + return { username: "test", password: "admin" }; + case "cart": + return { items: [{ id: "123", quantity: 123 }] }; + case "person": + return { name: "andrea", age: 27 }; + default: + throw new Error("unknown tag"); + } +} + +// ok, non-exhaustive cases but default case with throw +function mockPayload2( + str: P_TAG, +): PayloadContent[P_TAG] { + switch (str) { + case "auth": + return { username: "test", password: "admin" }; + case "cart": + return { items: [{ id: "123", quantity: 123 }] }; + default: + throw new Error("unhandled tag"); + } +} + +// ok, exhaustive cases +function mockPayload3( + str: P_TAG, +): PayloadContent[P_TAG] { + switch (str) { + case "auth": + return { username: "test", password: "admin" }; + case "cart": + return { items: [{ id: "123", quantity: 123 }] }; + case "person": + return { name: "andrea", age: 27 }; + } +} + +// error, non-exhaustive cases +function mockPayload4( + str: P_TAG, +): PayloadContent[P_TAG] { + switch (str) { + case "auth": + return { username: "test", password: "admin" }; + case "cart": + return { items: [{ id: "123", quantity: 123 }] }; + } +}