From 60963d7216266bca6ef3236f43913de703fe5c7a Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 13 Sep 2022 10:29:50 -0700 Subject: [PATCH] Discriminant of type `never` should never be matched (#50755) * Discriminant of type 'never' should never be matched * Add tests --- src/compiler/checker.ts | 2 +- .../neverAsDiscriminantType(strict=false).js | 143 +++++++++++++ ...erAsDiscriminantType(strict=false).symbols | 197 ++++++++++++++++++ ...everAsDiscriminantType(strict=false).types | 177 ++++++++++++++++ .../neverAsDiscriminantType(strict=true).js | 143 +++++++++++++ ...verAsDiscriminantType(strict=true).symbols | 197 ++++++++++++++++++ ...neverAsDiscriminantType(strict=true).types | 177 ++++++++++++++++ .../cases/compiler/neverAsDiscriminantType.ts | 66 ++++++ 8 files changed, 1101 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/neverAsDiscriminantType(strict=false).js create mode 100644 tests/baselines/reference/neverAsDiscriminantType(strict=false).symbols create mode 100644 tests/baselines/reference/neverAsDiscriminantType(strict=false).types create mode 100644 tests/baselines/reference/neverAsDiscriminantType(strict=true).js create mode 100644 tests/baselines/reference/neverAsDiscriminantType(strict=true).symbols create mode 100644 tests/baselines/reference/neverAsDiscriminantType(strict=true).types create mode 100644 tests/cases/compiler/neverAsDiscriminantType.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 724c3b48cc670..7504fee5a8425 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -25130,7 +25130,7 @@ namespace ts { const narrowedPropType = narrowType(propType); return filterType(type, t => { const discriminantType = getTypeOfPropertyOrIndexSignature(t, propName); - return !(narrowedPropType.flags & TypeFlags.Never) && areTypesComparable(narrowedPropType, discriminantType); + return !(discriminantType.flags & TypeFlags.Never) && !(narrowedPropType.flags & TypeFlags.Never) && areTypesComparable(narrowedPropType, discriminantType); }); } diff --git a/tests/baselines/reference/neverAsDiscriminantType(strict=false).js b/tests/baselines/reference/neverAsDiscriminantType(strict=false).js new file mode 100644 index 0000000000000..de1a5790cceef --- /dev/null +++ b/tests/baselines/reference/neverAsDiscriminantType(strict=false).js @@ -0,0 +1,143 @@ +//// [neverAsDiscriminantType.ts] +type Foo1 = { kind: 'a', a: number } | { kind: 'b' } | { kind: never }; + +function f1(foo: Foo1) { + if (foo.kind === 'a') { + foo.a; + } +} + +type Foo2 = { kind?: 'a', a: number } | { kind?: 'b' } | { kind?: never }; + +function f2(foo: Foo2) { + if (foo.kind === 'a') { + foo.a; + } +} + +// Repro from #50716 + +export interface GatewayPayloadStructure { + op: O + d: D + t?: T + s?: number +} + +export type GatewayPayload = { + [O in GatewayOpcode]: O extends GatewayOpcode.DISPATCH + ? { + [T in keyof GatewayEvents]: GatewayPayloadStructure + }[keyof GatewayEvents] + : GatewayPayloadStructure +}[GatewayOpcode] + +export interface GatewayParams { + [GatewayOpcode.HELLO]: { b: 1 } +} + +export enum GatewayOpcode { + DISPATCH = 0, + HEARTBEAT = 1, + IDENTIFY = 2, + PRESENCE_UPDATE = 3, + VOICE_STATE_UPDATE = 4, + RESUME = 6, + RECONNECT = 7, + REQUEST_GUILD_MEMBERS = 8, + INVALID_SESSION = 9, + HELLO = 10, + HEARTBEAT_ACK = 11, +} + +export interface GatewayEvents { + MESSAGE_CREATE: { a: 1 } + MESSAGE_UPDATE: { a: 2 } + MESSAGE_DELETE: { a: 3 } +} + +function assertMessage(event: { a: 1 }) { } + +export async function adaptSession(input: GatewayPayload) { + if (input.t === 'MESSAGE_CREATE') { + assertMessage(input.d) + } +} + + +//// [neverAsDiscriminantType.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 __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +exports.__esModule = true; +exports.adaptSession = exports.GatewayOpcode = void 0; +function f1(foo) { + if (foo.kind === 'a') { + foo.a; + } +} +function f2(foo) { + if (foo.kind === 'a') { + foo.a; + } +} +var GatewayOpcode; +(function (GatewayOpcode) { + GatewayOpcode[GatewayOpcode["DISPATCH"] = 0] = "DISPATCH"; + GatewayOpcode[GatewayOpcode["HEARTBEAT"] = 1] = "HEARTBEAT"; + GatewayOpcode[GatewayOpcode["IDENTIFY"] = 2] = "IDENTIFY"; + GatewayOpcode[GatewayOpcode["PRESENCE_UPDATE"] = 3] = "PRESENCE_UPDATE"; + GatewayOpcode[GatewayOpcode["VOICE_STATE_UPDATE"] = 4] = "VOICE_STATE_UPDATE"; + GatewayOpcode[GatewayOpcode["RESUME"] = 6] = "RESUME"; + GatewayOpcode[GatewayOpcode["RECONNECT"] = 7] = "RECONNECT"; + GatewayOpcode[GatewayOpcode["REQUEST_GUILD_MEMBERS"] = 8] = "REQUEST_GUILD_MEMBERS"; + GatewayOpcode[GatewayOpcode["INVALID_SESSION"] = 9] = "INVALID_SESSION"; + GatewayOpcode[GatewayOpcode["HELLO"] = 10] = "HELLO"; + GatewayOpcode[GatewayOpcode["HEARTBEAT_ACK"] = 11] = "HEARTBEAT_ACK"; +})(GatewayOpcode = exports.GatewayOpcode || (exports.GatewayOpcode = {})); +function assertMessage(event) { } +function adaptSession(input) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + if (input.t === 'MESSAGE_CREATE') { + assertMessage(input.d); + } + return [2 /*return*/]; + }); + }); +} +exports.adaptSession = adaptSession; diff --git a/tests/baselines/reference/neverAsDiscriminantType(strict=false).symbols b/tests/baselines/reference/neverAsDiscriminantType(strict=false).symbols new file mode 100644 index 0000000000000..376c5564573a5 --- /dev/null +++ b/tests/baselines/reference/neverAsDiscriminantType(strict=false).symbols @@ -0,0 +1,197 @@ +=== tests/cases/compiler/neverAsDiscriminantType.ts === +type Foo1 = { kind: 'a', a: number } | { kind: 'b' } | { kind: never }; +>Foo1 : Symbol(Foo1, Decl(neverAsDiscriminantType.ts, 0, 0)) +>kind : Symbol(kind, Decl(neverAsDiscriminantType.ts, 0, 13)) +>a : Symbol(a, Decl(neverAsDiscriminantType.ts, 0, 24)) +>kind : Symbol(kind, Decl(neverAsDiscriminantType.ts, 0, 40)) +>kind : Symbol(kind, Decl(neverAsDiscriminantType.ts, 0, 56)) + +function f1(foo: Foo1) { +>f1 : Symbol(f1, Decl(neverAsDiscriminantType.ts, 0, 71)) +>foo : Symbol(foo, Decl(neverAsDiscriminantType.ts, 2, 12)) +>Foo1 : Symbol(Foo1, Decl(neverAsDiscriminantType.ts, 0, 0)) + + if (foo.kind === 'a') { +>foo.kind : Symbol(kind, Decl(neverAsDiscriminantType.ts, 0, 13), Decl(neverAsDiscriminantType.ts, 0, 40), Decl(neverAsDiscriminantType.ts, 0, 56)) +>foo : Symbol(foo, Decl(neverAsDiscriminantType.ts, 2, 12)) +>kind : Symbol(kind, Decl(neverAsDiscriminantType.ts, 0, 13), Decl(neverAsDiscriminantType.ts, 0, 40), Decl(neverAsDiscriminantType.ts, 0, 56)) + + foo.a; +>foo.a : Symbol(a, Decl(neverAsDiscriminantType.ts, 0, 24)) +>foo : Symbol(foo, Decl(neverAsDiscriminantType.ts, 2, 12)) +>a : Symbol(a, Decl(neverAsDiscriminantType.ts, 0, 24)) + } +} + +type Foo2 = { kind?: 'a', a: number } | { kind?: 'b' } | { kind?: never }; +>Foo2 : Symbol(Foo2, Decl(neverAsDiscriminantType.ts, 6, 1)) +>kind : Symbol(kind, Decl(neverAsDiscriminantType.ts, 8, 13)) +>a : Symbol(a, Decl(neverAsDiscriminantType.ts, 8, 25)) +>kind : Symbol(kind, Decl(neverAsDiscriminantType.ts, 8, 41)) +>kind : Symbol(kind, Decl(neverAsDiscriminantType.ts, 8, 58)) + +function f2(foo: Foo2) { +>f2 : Symbol(f2, Decl(neverAsDiscriminantType.ts, 8, 74)) +>foo : Symbol(foo, Decl(neverAsDiscriminantType.ts, 10, 12)) +>Foo2 : Symbol(Foo2, Decl(neverAsDiscriminantType.ts, 6, 1)) + + if (foo.kind === 'a') { +>foo.kind : Symbol(kind, Decl(neverAsDiscriminantType.ts, 8, 13), Decl(neverAsDiscriminantType.ts, 8, 41), Decl(neverAsDiscriminantType.ts, 8, 58)) +>foo : Symbol(foo, Decl(neverAsDiscriminantType.ts, 10, 12)) +>kind : Symbol(kind, Decl(neverAsDiscriminantType.ts, 8, 13), Decl(neverAsDiscriminantType.ts, 8, 41), Decl(neverAsDiscriminantType.ts, 8, 58)) + + foo.a; +>foo.a : Symbol(a, Decl(neverAsDiscriminantType.ts, 8, 25)) +>foo : Symbol(foo, Decl(neverAsDiscriminantType.ts, 10, 12)) +>a : Symbol(a, Decl(neverAsDiscriminantType.ts, 8, 25)) + } +} + +// Repro from #50716 + +export interface GatewayPayloadStructure { +>GatewayPayloadStructure : Symbol(GatewayPayloadStructure, Decl(neverAsDiscriminantType.ts, 14, 1)) +>O : Symbol(O, Decl(neverAsDiscriminantType.ts, 18, 41)) +>GatewayOpcode : Symbol(GatewayOpcode, Decl(neverAsDiscriminantType.ts, 35, 1)) +>T : Symbol(T, Decl(neverAsDiscriminantType.ts, 18, 65)) +>GatewayEvents : Symbol(GatewayEvents, Decl(neverAsDiscriminantType.ts, 49, 1)) +>D : Symbol(D, Decl(neverAsDiscriminantType.ts, 18, 96)) + + op: O +>op : Symbol(GatewayPayloadStructure.op, Decl(neverAsDiscriminantType.ts, 18, 101)) +>O : Symbol(O, Decl(neverAsDiscriminantType.ts, 18, 41)) + + d: D +>d : Symbol(GatewayPayloadStructure.d, Decl(neverAsDiscriminantType.ts, 19, 9)) +>D : Symbol(D, Decl(neverAsDiscriminantType.ts, 18, 96)) + + t?: T +>t : Symbol(GatewayPayloadStructure.t, Decl(neverAsDiscriminantType.ts, 20, 8)) +>T : Symbol(T, Decl(neverAsDiscriminantType.ts, 18, 65)) + + s?: number +>s : Symbol(GatewayPayloadStructure.s, Decl(neverAsDiscriminantType.ts, 21, 9)) +} + +export type GatewayPayload = { +>GatewayPayload : Symbol(GatewayPayload, Decl(neverAsDiscriminantType.ts, 23, 1)) + + [O in GatewayOpcode]: O extends GatewayOpcode.DISPATCH +>O : Symbol(O, Decl(neverAsDiscriminantType.ts, 26, 5)) +>GatewayOpcode : Symbol(GatewayOpcode, Decl(neverAsDiscriminantType.ts, 35, 1)) +>O : Symbol(O, Decl(neverAsDiscriminantType.ts, 26, 5)) +>GatewayOpcode : Symbol(GatewayOpcode, Decl(neverAsDiscriminantType.ts, 35, 1)) +>DISPATCH : Symbol(GatewayOpcode.DISPATCH, Decl(neverAsDiscriminantType.ts, 37, 27)) + + ? { + [T in keyof GatewayEvents]: GatewayPayloadStructure +>T : Symbol(T, Decl(neverAsDiscriminantType.ts, 28, 9)) +>GatewayEvents : Symbol(GatewayEvents, Decl(neverAsDiscriminantType.ts, 49, 1)) +>GatewayPayloadStructure : Symbol(GatewayPayloadStructure, Decl(neverAsDiscriminantType.ts, 14, 1)) +>GatewayOpcode : Symbol(GatewayOpcode, Decl(neverAsDiscriminantType.ts, 35, 1)) +>DISPATCH : Symbol(GatewayOpcode.DISPATCH, Decl(neverAsDiscriminantType.ts, 37, 27)) +>T : Symbol(T, Decl(neverAsDiscriminantType.ts, 28, 9)) +>GatewayEvents : Symbol(GatewayEvents, Decl(neverAsDiscriminantType.ts, 49, 1)) +>T : Symbol(T, Decl(neverAsDiscriminantType.ts, 28, 9)) + + }[keyof GatewayEvents] +>GatewayEvents : Symbol(GatewayEvents, Decl(neverAsDiscriminantType.ts, 49, 1)) + + : GatewayPayloadStructure +>GatewayPayloadStructure : Symbol(GatewayPayloadStructure, Decl(neverAsDiscriminantType.ts, 14, 1)) +>O : Symbol(O, Decl(neverAsDiscriminantType.ts, 26, 5)) +>O : Symbol(O, Decl(neverAsDiscriminantType.ts, 26, 5)) +>GatewayParams : Symbol(GatewayParams, Decl(neverAsDiscriminantType.ts, 31, 16)) +>GatewayParams : Symbol(GatewayParams, Decl(neverAsDiscriminantType.ts, 31, 16)) +>O : Symbol(O, Decl(neverAsDiscriminantType.ts, 26, 5)) + +}[GatewayOpcode] +>GatewayOpcode : Symbol(GatewayOpcode, Decl(neverAsDiscriminantType.ts, 35, 1)) + +export interface GatewayParams { +>GatewayParams : Symbol(GatewayParams, Decl(neverAsDiscriminantType.ts, 31, 16)) + + [GatewayOpcode.HELLO]: { b: 1 } +>[GatewayOpcode.HELLO] : Symbol(GatewayParams[GatewayOpcode.HELLO], Decl(neverAsDiscriminantType.ts, 33, 32)) +>GatewayOpcode.HELLO : Symbol(GatewayOpcode.HELLO, Decl(neverAsDiscriminantType.ts, 46, 24)) +>GatewayOpcode : Symbol(GatewayOpcode, Decl(neverAsDiscriminantType.ts, 35, 1)) +>HELLO : Symbol(GatewayOpcode.HELLO, Decl(neverAsDiscriminantType.ts, 46, 24)) +>b : Symbol(b, Decl(neverAsDiscriminantType.ts, 34, 28)) +} + +export enum GatewayOpcode { +>GatewayOpcode : Symbol(GatewayOpcode, Decl(neverAsDiscriminantType.ts, 35, 1)) + + DISPATCH = 0, +>DISPATCH : Symbol(GatewayOpcode.DISPATCH, Decl(neverAsDiscriminantType.ts, 37, 27)) + + HEARTBEAT = 1, +>HEARTBEAT : Symbol(GatewayOpcode.HEARTBEAT, Decl(neverAsDiscriminantType.ts, 38, 17)) + + IDENTIFY = 2, +>IDENTIFY : Symbol(GatewayOpcode.IDENTIFY, Decl(neverAsDiscriminantType.ts, 39, 18)) + + PRESENCE_UPDATE = 3, +>PRESENCE_UPDATE : Symbol(GatewayOpcode.PRESENCE_UPDATE, Decl(neverAsDiscriminantType.ts, 40, 17)) + + VOICE_STATE_UPDATE = 4, +>VOICE_STATE_UPDATE : Symbol(GatewayOpcode.VOICE_STATE_UPDATE, Decl(neverAsDiscriminantType.ts, 41, 24)) + + RESUME = 6, +>RESUME : Symbol(GatewayOpcode.RESUME, Decl(neverAsDiscriminantType.ts, 42, 27)) + + RECONNECT = 7, +>RECONNECT : Symbol(GatewayOpcode.RECONNECT, Decl(neverAsDiscriminantType.ts, 43, 15)) + + REQUEST_GUILD_MEMBERS = 8, +>REQUEST_GUILD_MEMBERS : Symbol(GatewayOpcode.REQUEST_GUILD_MEMBERS, Decl(neverAsDiscriminantType.ts, 44, 18)) + + INVALID_SESSION = 9, +>INVALID_SESSION : Symbol(GatewayOpcode.INVALID_SESSION, Decl(neverAsDiscriminantType.ts, 45, 30)) + + HELLO = 10, +>HELLO : Symbol(GatewayOpcode.HELLO, Decl(neverAsDiscriminantType.ts, 46, 24)) + + HEARTBEAT_ACK = 11, +>HEARTBEAT_ACK : Symbol(GatewayOpcode.HEARTBEAT_ACK, Decl(neverAsDiscriminantType.ts, 47, 15)) +} + +export interface GatewayEvents { +>GatewayEvents : Symbol(GatewayEvents, Decl(neverAsDiscriminantType.ts, 49, 1)) + + MESSAGE_CREATE: { a: 1 } +>MESSAGE_CREATE : Symbol(GatewayEvents.MESSAGE_CREATE, Decl(neverAsDiscriminantType.ts, 51, 32)) +>a : Symbol(a, Decl(neverAsDiscriminantType.ts, 52, 21)) + + MESSAGE_UPDATE: { a: 2 } +>MESSAGE_UPDATE : Symbol(GatewayEvents.MESSAGE_UPDATE, Decl(neverAsDiscriminantType.ts, 52, 28)) +>a : Symbol(a, Decl(neverAsDiscriminantType.ts, 53, 21)) + + MESSAGE_DELETE: { a: 3 } +>MESSAGE_DELETE : Symbol(GatewayEvents.MESSAGE_DELETE, Decl(neverAsDiscriminantType.ts, 53, 28)) +>a : Symbol(a, Decl(neverAsDiscriminantType.ts, 54, 21)) +} + +function assertMessage(event: { a: 1 }) { } +>assertMessage : Symbol(assertMessage, Decl(neverAsDiscriminantType.ts, 55, 1)) +>event : Symbol(event, Decl(neverAsDiscriminantType.ts, 57, 23)) +>a : Symbol(a, Decl(neverAsDiscriminantType.ts, 57, 31)) + +export async function adaptSession(input: GatewayPayload) { +>adaptSession : Symbol(adaptSession, Decl(neverAsDiscriminantType.ts, 57, 43)) +>input : Symbol(input, Decl(neverAsDiscriminantType.ts, 59, 35)) +>GatewayPayload : Symbol(GatewayPayload, Decl(neverAsDiscriminantType.ts, 23, 1)) + + if (input.t === 'MESSAGE_CREATE') { +>input.t : Symbol(GatewayPayloadStructure.t, Decl(neverAsDiscriminantType.ts, 20, 8), Decl(neverAsDiscriminantType.ts, 20, 8), Decl(neverAsDiscriminantType.ts, 20, 8), Decl(neverAsDiscriminantType.ts, 20, 8), Decl(neverAsDiscriminantType.ts, 20, 8) ... and 8 more) +>input : Symbol(input, Decl(neverAsDiscriminantType.ts, 59, 35)) +>t : Symbol(GatewayPayloadStructure.t, Decl(neverAsDiscriminantType.ts, 20, 8), Decl(neverAsDiscriminantType.ts, 20, 8), Decl(neverAsDiscriminantType.ts, 20, 8), Decl(neverAsDiscriminantType.ts, 20, 8), Decl(neverAsDiscriminantType.ts, 20, 8) ... and 8 more) + + assertMessage(input.d) +>assertMessage : Symbol(assertMessage, Decl(neverAsDiscriminantType.ts, 55, 1)) +>input.d : Symbol(GatewayPayloadStructure.d, Decl(neverAsDiscriminantType.ts, 19, 9)) +>input : Symbol(input, Decl(neverAsDiscriminantType.ts, 59, 35)) +>d : Symbol(GatewayPayloadStructure.d, Decl(neverAsDiscriminantType.ts, 19, 9)) + } +} + diff --git a/tests/baselines/reference/neverAsDiscriminantType(strict=false).types b/tests/baselines/reference/neverAsDiscriminantType(strict=false).types new file mode 100644 index 0000000000000..0aa3c7c0942c4 --- /dev/null +++ b/tests/baselines/reference/neverAsDiscriminantType(strict=false).types @@ -0,0 +1,177 @@ +=== tests/cases/compiler/neverAsDiscriminantType.ts === +type Foo1 = { kind: 'a', a: number } | { kind: 'b' } | { kind: never }; +>Foo1 : { kind: 'a'; a: number; } | { kind: 'b'; } | { kind: never; } +>kind : "a" +>a : number +>kind : "b" +>kind : never + +function f1(foo: Foo1) { +>f1 : (foo: Foo1) => void +>foo : Foo1 + + if (foo.kind === 'a') { +>foo.kind === 'a' : boolean +>foo.kind : "a" | "b" +>foo : Foo1 +>kind : "a" | "b" +>'a' : "a" + + foo.a; +>foo.a : number +>foo : { kind: "a"; a: number; } +>a : number + } +} + +type Foo2 = { kind?: 'a', a: number } | { kind?: 'b' } | { kind?: never }; +>Foo2 : { kind?: 'a'; a: number; } | { kind?: 'b'; } | { kind?: never; } +>kind : "a" +>a : number +>kind : "b" +>kind : never + +function f2(foo: Foo2) { +>f2 : (foo: Foo2) => void +>foo : Foo2 + + if (foo.kind === 'a') { +>foo.kind === 'a' : boolean +>foo.kind : "a" | "b" +>foo : Foo2 +>kind : "a" | "b" +>'a' : "a" + + foo.a; +>foo.a : number +>foo : { kind?: "a"; a: number; } +>a : number + } +} + +// Repro from #50716 + +export interface GatewayPayloadStructure { + op: O +>op : O + + d: D +>d : D + + t?: T +>t : T + + s?: number +>s : number +} + +export type GatewayPayload = { +>GatewayPayload : GatewayPayloadStructure | GatewayPayloadStructure | GatewayPayloadStructure | GatewayPayloadStructure | GatewayPayloadStructure | GatewayPayloadStructure | GatewayPayloadStructure | GatewayPayloadStructure | GatewayPayloadStructure | GatewayPayloadStructure | GatewayPayloadStructure | GatewayPayloadStructure | GatewayPayloadStructure + + [O in GatewayOpcode]: O extends GatewayOpcode.DISPATCH +>GatewayOpcode : any + + ? { + [T in keyof GatewayEvents]: GatewayPayloadStructure +>GatewayOpcode : any + + }[keyof GatewayEvents] + : GatewayPayloadStructure +}[GatewayOpcode] + +export interface GatewayParams { + [GatewayOpcode.HELLO]: { b: 1 } +>[GatewayOpcode.HELLO] : { b: 1; } +>GatewayOpcode.HELLO : GatewayOpcode.HELLO +>GatewayOpcode : typeof GatewayOpcode +>HELLO : GatewayOpcode.HELLO +>b : 1 +} + +export enum GatewayOpcode { +>GatewayOpcode : GatewayOpcode + + DISPATCH = 0, +>DISPATCH : GatewayOpcode.DISPATCH +>0 : 0 + + HEARTBEAT = 1, +>HEARTBEAT : GatewayOpcode.HEARTBEAT +>1 : 1 + + IDENTIFY = 2, +>IDENTIFY : GatewayOpcode.IDENTIFY +>2 : 2 + + PRESENCE_UPDATE = 3, +>PRESENCE_UPDATE : GatewayOpcode.PRESENCE_UPDATE +>3 : 3 + + VOICE_STATE_UPDATE = 4, +>VOICE_STATE_UPDATE : GatewayOpcode.VOICE_STATE_UPDATE +>4 : 4 + + RESUME = 6, +>RESUME : GatewayOpcode.RESUME +>6 : 6 + + RECONNECT = 7, +>RECONNECT : GatewayOpcode.RECONNECT +>7 : 7 + + REQUEST_GUILD_MEMBERS = 8, +>REQUEST_GUILD_MEMBERS : GatewayOpcode.REQUEST_GUILD_MEMBERS +>8 : 8 + + INVALID_SESSION = 9, +>INVALID_SESSION : GatewayOpcode.INVALID_SESSION +>9 : 9 + + HELLO = 10, +>HELLO : GatewayOpcode.HELLO +>10 : 10 + + HEARTBEAT_ACK = 11, +>HEARTBEAT_ACK : GatewayOpcode.HEARTBEAT_ACK +>11 : 11 +} + +export interface GatewayEvents { + MESSAGE_CREATE: { a: 1 } +>MESSAGE_CREATE : { a: 1; } +>a : 1 + + MESSAGE_UPDATE: { a: 2 } +>MESSAGE_UPDATE : { a: 2; } +>a : 2 + + MESSAGE_DELETE: { a: 3 } +>MESSAGE_DELETE : { a: 3; } +>a : 3 +} + +function assertMessage(event: { a: 1 }) { } +>assertMessage : (event: { a: 1;}) => void +>event : { a: 1; } +>a : 1 + +export async function adaptSession(input: GatewayPayload) { +>adaptSession : (input: GatewayPayload) => Promise +>input : GatewayPayload + + if (input.t === 'MESSAGE_CREATE') { +>input.t === 'MESSAGE_CREATE' : boolean +>input.t : "MESSAGE_CREATE" | "MESSAGE_UPDATE" | "MESSAGE_DELETE" +>input : GatewayPayload +>t : "MESSAGE_CREATE" | "MESSAGE_UPDATE" | "MESSAGE_DELETE" +>'MESSAGE_CREATE' : "MESSAGE_CREATE" + + assertMessage(input.d) +>assertMessage(input.d) : void +>assertMessage : (event: { a: 1; }) => void +>input.d : { a: 1; } +>input : GatewayPayloadStructure +>d : { a: 1; } + } +} + diff --git a/tests/baselines/reference/neverAsDiscriminantType(strict=true).js b/tests/baselines/reference/neverAsDiscriminantType(strict=true).js new file mode 100644 index 0000000000000..de1a5790cceef --- /dev/null +++ b/tests/baselines/reference/neverAsDiscriminantType(strict=true).js @@ -0,0 +1,143 @@ +//// [neverAsDiscriminantType.ts] +type Foo1 = { kind: 'a', a: number } | { kind: 'b' } | { kind: never }; + +function f1(foo: Foo1) { + if (foo.kind === 'a') { + foo.a; + } +} + +type Foo2 = { kind?: 'a', a: number } | { kind?: 'b' } | { kind?: never }; + +function f2(foo: Foo2) { + if (foo.kind === 'a') { + foo.a; + } +} + +// Repro from #50716 + +export interface GatewayPayloadStructure { + op: O + d: D + t?: T + s?: number +} + +export type GatewayPayload = { + [O in GatewayOpcode]: O extends GatewayOpcode.DISPATCH + ? { + [T in keyof GatewayEvents]: GatewayPayloadStructure + }[keyof GatewayEvents] + : GatewayPayloadStructure +}[GatewayOpcode] + +export interface GatewayParams { + [GatewayOpcode.HELLO]: { b: 1 } +} + +export enum GatewayOpcode { + DISPATCH = 0, + HEARTBEAT = 1, + IDENTIFY = 2, + PRESENCE_UPDATE = 3, + VOICE_STATE_UPDATE = 4, + RESUME = 6, + RECONNECT = 7, + REQUEST_GUILD_MEMBERS = 8, + INVALID_SESSION = 9, + HELLO = 10, + HEARTBEAT_ACK = 11, +} + +export interface GatewayEvents { + MESSAGE_CREATE: { a: 1 } + MESSAGE_UPDATE: { a: 2 } + MESSAGE_DELETE: { a: 3 } +} + +function assertMessage(event: { a: 1 }) { } + +export async function adaptSession(input: GatewayPayload) { + if (input.t === 'MESSAGE_CREATE') { + assertMessage(input.d) + } +} + + +//// [neverAsDiscriminantType.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 __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +exports.__esModule = true; +exports.adaptSession = exports.GatewayOpcode = void 0; +function f1(foo) { + if (foo.kind === 'a') { + foo.a; + } +} +function f2(foo) { + if (foo.kind === 'a') { + foo.a; + } +} +var GatewayOpcode; +(function (GatewayOpcode) { + GatewayOpcode[GatewayOpcode["DISPATCH"] = 0] = "DISPATCH"; + GatewayOpcode[GatewayOpcode["HEARTBEAT"] = 1] = "HEARTBEAT"; + GatewayOpcode[GatewayOpcode["IDENTIFY"] = 2] = "IDENTIFY"; + GatewayOpcode[GatewayOpcode["PRESENCE_UPDATE"] = 3] = "PRESENCE_UPDATE"; + GatewayOpcode[GatewayOpcode["VOICE_STATE_UPDATE"] = 4] = "VOICE_STATE_UPDATE"; + GatewayOpcode[GatewayOpcode["RESUME"] = 6] = "RESUME"; + GatewayOpcode[GatewayOpcode["RECONNECT"] = 7] = "RECONNECT"; + GatewayOpcode[GatewayOpcode["REQUEST_GUILD_MEMBERS"] = 8] = "REQUEST_GUILD_MEMBERS"; + GatewayOpcode[GatewayOpcode["INVALID_SESSION"] = 9] = "INVALID_SESSION"; + GatewayOpcode[GatewayOpcode["HELLO"] = 10] = "HELLO"; + GatewayOpcode[GatewayOpcode["HEARTBEAT_ACK"] = 11] = "HEARTBEAT_ACK"; +})(GatewayOpcode = exports.GatewayOpcode || (exports.GatewayOpcode = {})); +function assertMessage(event) { } +function adaptSession(input) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + if (input.t === 'MESSAGE_CREATE') { + assertMessage(input.d); + } + return [2 /*return*/]; + }); + }); +} +exports.adaptSession = adaptSession; diff --git a/tests/baselines/reference/neverAsDiscriminantType(strict=true).symbols b/tests/baselines/reference/neverAsDiscriminantType(strict=true).symbols new file mode 100644 index 0000000000000..376c5564573a5 --- /dev/null +++ b/tests/baselines/reference/neverAsDiscriminantType(strict=true).symbols @@ -0,0 +1,197 @@ +=== tests/cases/compiler/neverAsDiscriminantType.ts === +type Foo1 = { kind: 'a', a: number } | { kind: 'b' } | { kind: never }; +>Foo1 : Symbol(Foo1, Decl(neverAsDiscriminantType.ts, 0, 0)) +>kind : Symbol(kind, Decl(neverAsDiscriminantType.ts, 0, 13)) +>a : Symbol(a, Decl(neverAsDiscriminantType.ts, 0, 24)) +>kind : Symbol(kind, Decl(neverAsDiscriminantType.ts, 0, 40)) +>kind : Symbol(kind, Decl(neverAsDiscriminantType.ts, 0, 56)) + +function f1(foo: Foo1) { +>f1 : Symbol(f1, Decl(neverAsDiscriminantType.ts, 0, 71)) +>foo : Symbol(foo, Decl(neverAsDiscriminantType.ts, 2, 12)) +>Foo1 : Symbol(Foo1, Decl(neverAsDiscriminantType.ts, 0, 0)) + + if (foo.kind === 'a') { +>foo.kind : Symbol(kind, Decl(neverAsDiscriminantType.ts, 0, 13), Decl(neverAsDiscriminantType.ts, 0, 40), Decl(neverAsDiscriminantType.ts, 0, 56)) +>foo : Symbol(foo, Decl(neverAsDiscriminantType.ts, 2, 12)) +>kind : Symbol(kind, Decl(neverAsDiscriminantType.ts, 0, 13), Decl(neverAsDiscriminantType.ts, 0, 40), Decl(neverAsDiscriminantType.ts, 0, 56)) + + foo.a; +>foo.a : Symbol(a, Decl(neverAsDiscriminantType.ts, 0, 24)) +>foo : Symbol(foo, Decl(neverAsDiscriminantType.ts, 2, 12)) +>a : Symbol(a, Decl(neverAsDiscriminantType.ts, 0, 24)) + } +} + +type Foo2 = { kind?: 'a', a: number } | { kind?: 'b' } | { kind?: never }; +>Foo2 : Symbol(Foo2, Decl(neverAsDiscriminantType.ts, 6, 1)) +>kind : Symbol(kind, Decl(neverAsDiscriminantType.ts, 8, 13)) +>a : Symbol(a, Decl(neverAsDiscriminantType.ts, 8, 25)) +>kind : Symbol(kind, Decl(neverAsDiscriminantType.ts, 8, 41)) +>kind : Symbol(kind, Decl(neverAsDiscriminantType.ts, 8, 58)) + +function f2(foo: Foo2) { +>f2 : Symbol(f2, Decl(neverAsDiscriminantType.ts, 8, 74)) +>foo : Symbol(foo, Decl(neverAsDiscriminantType.ts, 10, 12)) +>Foo2 : Symbol(Foo2, Decl(neverAsDiscriminantType.ts, 6, 1)) + + if (foo.kind === 'a') { +>foo.kind : Symbol(kind, Decl(neverAsDiscriminantType.ts, 8, 13), Decl(neverAsDiscriminantType.ts, 8, 41), Decl(neverAsDiscriminantType.ts, 8, 58)) +>foo : Symbol(foo, Decl(neverAsDiscriminantType.ts, 10, 12)) +>kind : Symbol(kind, Decl(neverAsDiscriminantType.ts, 8, 13), Decl(neverAsDiscriminantType.ts, 8, 41), Decl(neverAsDiscriminantType.ts, 8, 58)) + + foo.a; +>foo.a : Symbol(a, Decl(neverAsDiscriminantType.ts, 8, 25)) +>foo : Symbol(foo, Decl(neverAsDiscriminantType.ts, 10, 12)) +>a : Symbol(a, Decl(neverAsDiscriminantType.ts, 8, 25)) + } +} + +// Repro from #50716 + +export interface GatewayPayloadStructure { +>GatewayPayloadStructure : Symbol(GatewayPayloadStructure, Decl(neverAsDiscriminantType.ts, 14, 1)) +>O : Symbol(O, Decl(neverAsDiscriminantType.ts, 18, 41)) +>GatewayOpcode : Symbol(GatewayOpcode, Decl(neverAsDiscriminantType.ts, 35, 1)) +>T : Symbol(T, Decl(neverAsDiscriminantType.ts, 18, 65)) +>GatewayEvents : Symbol(GatewayEvents, Decl(neverAsDiscriminantType.ts, 49, 1)) +>D : Symbol(D, Decl(neverAsDiscriminantType.ts, 18, 96)) + + op: O +>op : Symbol(GatewayPayloadStructure.op, Decl(neverAsDiscriminantType.ts, 18, 101)) +>O : Symbol(O, Decl(neverAsDiscriminantType.ts, 18, 41)) + + d: D +>d : Symbol(GatewayPayloadStructure.d, Decl(neverAsDiscriminantType.ts, 19, 9)) +>D : Symbol(D, Decl(neverAsDiscriminantType.ts, 18, 96)) + + t?: T +>t : Symbol(GatewayPayloadStructure.t, Decl(neverAsDiscriminantType.ts, 20, 8)) +>T : Symbol(T, Decl(neverAsDiscriminantType.ts, 18, 65)) + + s?: number +>s : Symbol(GatewayPayloadStructure.s, Decl(neverAsDiscriminantType.ts, 21, 9)) +} + +export type GatewayPayload = { +>GatewayPayload : Symbol(GatewayPayload, Decl(neverAsDiscriminantType.ts, 23, 1)) + + [O in GatewayOpcode]: O extends GatewayOpcode.DISPATCH +>O : Symbol(O, Decl(neverAsDiscriminantType.ts, 26, 5)) +>GatewayOpcode : Symbol(GatewayOpcode, Decl(neverAsDiscriminantType.ts, 35, 1)) +>O : Symbol(O, Decl(neverAsDiscriminantType.ts, 26, 5)) +>GatewayOpcode : Symbol(GatewayOpcode, Decl(neverAsDiscriminantType.ts, 35, 1)) +>DISPATCH : Symbol(GatewayOpcode.DISPATCH, Decl(neverAsDiscriminantType.ts, 37, 27)) + + ? { + [T in keyof GatewayEvents]: GatewayPayloadStructure +>T : Symbol(T, Decl(neverAsDiscriminantType.ts, 28, 9)) +>GatewayEvents : Symbol(GatewayEvents, Decl(neverAsDiscriminantType.ts, 49, 1)) +>GatewayPayloadStructure : Symbol(GatewayPayloadStructure, Decl(neverAsDiscriminantType.ts, 14, 1)) +>GatewayOpcode : Symbol(GatewayOpcode, Decl(neverAsDiscriminantType.ts, 35, 1)) +>DISPATCH : Symbol(GatewayOpcode.DISPATCH, Decl(neverAsDiscriminantType.ts, 37, 27)) +>T : Symbol(T, Decl(neverAsDiscriminantType.ts, 28, 9)) +>GatewayEvents : Symbol(GatewayEvents, Decl(neverAsDiscriminantType.ts, 49, 1)) +>T : Symbol(T, Decl(neverAsDiscriminantType.ts, 28, 9)) + + }[keyof GatewayEvents] +>GatewayEvents : Symbol(GatewayEvents, Decl(neverAsDiscriminantType.ts, 49, 1)) + + : GatewayPayloadStructure +>GatewayPayloadStructure : Symbol(GatewayPayloadStructure, Decl(neverAsDiscriminantType.ts, 14, 1)) +>O : Symbol(O, Decl(neverAsDiscriminantType.ts, 26, 5)) +>O : Symbol(O, Decl(neverAsDiscriminantType.ts, 26, 5)) +>GatewayParams : Symbol(GatewayParams, Decl(neverAsDiscriminantType.ts, 31, 16)) +>GatewayParams : Symbol(GatewayParams, Decl(neverAsDiscriminantType.ts, 31, 16)) +>O : Symbol(O, Decl(neverAsDiscriminantType.ts, 26, 5)) + +}[GatewayOpcode] +>GatewayOpcode : Symbol(GatewayOpcode, Decl(neverAsDiscriminantType.ts, 35, 1)) + +export interface GatewayParams { +>GatewayParams : Symbol(GatewayParams, Decl(neverAsDiscriminantType.ts, 31, 16)) + + [GatewayOpcode.HELLO]: { b: 1 } +>[GatewayOpcode.HELLO] : Symbol(GatewayParams[GatewayOpcode.HELLO], Decl(neverAsDiscriminantType.ts, 33, 32)) +>GatewayOpcode.HELLO : Symbol(GatewayOpcode.HELLO, Decl(neverAsDiscriminantType.ts, 46, 24)) +>GatewayOpcode : Symbol(GatewayOpcode, Decl(neverAsDiscriminantType.ts, 35, 1)) +>HELLO : Symbol(GatewayOpcode.HELLO, Decl(neverAsDiscriminantType.ts, 46, 24)) +>b : Symbol(b, Decl(neverAsDiscriminantType.ts, 34, 28)) +} + +export enum GatewayOpcode { +>GatewayOpcode : Symbol(GatewayOpcode, Decl(neverAsDiscriminantType.ts, 35, 1)) + + DISPATCH = 0, +>DISPATCH : Symbol(GatewayOpcode.DISPATCH, Decl(neverAsDiscriminantType.ts, 37, 27)) + + HEARTBEAT = 1, +>HEARTBEAT : Symbol(GatewayOpcode.HEARTBEAT, Decl(neverAsDiscriminantType.ts, 38, 17)) + + IDENTIFY = 2, +>IDENTIFY : Symbol(GatewayOpcode.IDENTIFY, Decl(neverAsDiscriminantType.ts, 39, 18)) + + PRESENCE_UPDATE = 3, +>PRESENCE_UPDATE : Symbol(GatewayOpcode.PRESENCE_UPDATE, Decl(neverAsDiscriminantType.ts, 40, 17)) + + VOICE_STATE_UPDATE = 4, +>VOICE_STATE_UPDATE : Symbol(GatewayOpcode.VOICE_STATE_UPDATE, Decl(neverAsDiscriminantType.ts, 41, 24)) + + RESUME = 6, +>RESUME : Symbol(GatewayOpcode.RESUME, Decl(neverAsDiscriminantType.ts, 42, 27)) + + RECONNECT = 7, +>RECONNECT : Symbol(GatewayOpcode.RECONNECT, Decl(neverAsDiscriminantType.ts, 43, 15)) + + REQUEST_GUILD_MEMBERS = 8, +>REQUEST_GUILD_MEMBERS : Symbol(GatewayOpcode.REQUEST_GUILD_MEMBERS, Decl(neverAsDiscriminantType.ts, 44, 18)) + + INVALID_SESSION = 9, +>INVALID_SESSION : Symbol(GatewayOpcode.INVALID_SESSION, Decl(neverAsDiscriminantType.ts, 45, 30)) + + HELLO = 10, +>HELLO : Symbol(GatewayOpcode.HELLO, Decl(neverAsDiscriminantType.ts, 46, 24)) + + HEARTBEAT_ACK = 11, +>HEARTBEAT_ACK : Symbol(GatewayOpcode.HEARTBEAT_ACK, Decl(neverAsDiscriminantType.ts, 47, 15)) +} + +export interface GatewayEvents { +>GatewayEvents : Symbol(GatewayEvents, Decl(neverAsDiscriminantType.ts, 49, 1)) + + MESSAGE_CREATE: { a: 1 } +>MESSAGE_CREATE : Symbol(GatewayEvents.MESSAGE_CREATE, Decl(neverAsDiscriminantType.ts, 51, 32)) +>a : Symbol(a, Decl(neverAsDiscriminantType.ts, 52, 21)) + + MESSAGE_UPDATE: { a: 2 } +>MESSAGE_UPDATE : Symbol(GatewayEvents.MESSAGE_UPDATE, Decl(neverAsDiscriminantType.ts, 52, 28)) +>a : Symbol(a, Decl(neverAsDiscriminantType.ts, 53, 21)) + + MESSAGE_DELETE: { a: 3 } +>MESSAGE_DELETE : Symbol(GatewayEvents.MESSAGE_DELETE, Decl(neverAsDiscriminantType.ts, 53, 28)) +>a : Symbol(a, Decl(neverAsDiscriminantType.ts, 54, 21)) +} + +function assertMessage(event: { a: 1 }) { } +>assertMessage : Symbol(assertMessage, Decl(neverAsDiscriminantType.ts, 55, 1)) +>event : Symbol(event, Decl(neverAsDiscriminantType.ts, 57, 23)) +>a : Symbol(a, Decl(neverAsDiscriminantType.ts, 57, 31)) + +export async function adaptSession(input: GatewayPayload) { +>adaptSession : Symbol(adaptSession, Decl(neverAsDiscriminantType.ts, 57, 43)) +>input : Symbol(input, Decl(neverAsDiscriminantType.ts, 59, 35)) +>GatewayPayload : Symbol(GatewayPayload, Decl(neverAsDiscriminantType.ts, 23, 1)) + + if (input.t === 'MESSAGE_CREATE') { +>input.t : Symbol(GatewayPayloadStructure.t, Decl(neverAsDiscriminantType.ts, 20, 8), Decl(neverAsDiscriminantType.ts, 20, 8), Decl(neverAsDiscriminantType.ts, 20, 8), Decl(neverAsDiscriminantType.ts, 20, 8), Decl(neverAsDiscriminantType.ts, 20, 8) ... and 8 more) +>input : Symbol(input, Decl(neverAsDiscriminantType.ts, 59, 35)) +>t : Symbol(GatewayPayloadStructure.t, Decl(neverAsDiscriminantType.ts, 20, 8), Decl(neverAsDiscriminantType.ts, 20, 8), Decl(neverAsDiscriminantType.ts, 20, 8), Decl(neverAsDiscriminantType.ts, 20, 8), Decl(neverAsDiscriminantType.ts, 20, 8) ... and 8 more) + + assertMessage(input.d) +>assertMessage : Symbol(assertMessage, Decl(neverAsDiscriminantType.ts, 55, 1)) +>input.d : Symbol(GatewayPayloadStructure.d, Decl(neverAsDiscriminantType.ts, 19, 9)) +>input : Symbol(input, Decl(neverAsDiscriminantType.ts, 59, 35)) +>d : Symbol(GatewayPayloadStructure.d, Decl(neverAsDiscriminantType.ts, 19, 9)) + } +} + diff --git a/tests/baselines/reference/neverAsDiscriminantType(strict=true).types b/tests/baselines/reference/neverAsDiscriminantType(strict=true).types new file mode 100644 index 0000000000000..d7bc16c7309b8 --- /dev/null +++ b/tests/baselines/reference/neverAsDiscriminantType(strict=true).types @@ -0,0 +1,177 @@ +=== tests/cases/compiler/neverAsDiscriminantType.ts === +type Foo1 = { kind: 'a', a: number } | { kind: 'b' } | { kind: never }; +>Foo1 : { kind: 'a'; a: number; } | { kind: 'b'; } | { kind: never; } +>kind : "a" +>a : number +>kind : "b" +>kind : never + +function f1(foo: Foo1) { +>f1 : (foo: Foo1) => void +>foo : Foo1 + + if (foo.kind === 'a') { +>foo.kind === 'a' : boolean +>foo.kind : "a" | "b" +>foo : Foo1 +>kind : "a" | "b" +>'a' : "a" + + foo.a; +>foo.a : number +>foo : { kind: "a"; a: number; } +>a : number + } +} + +type Foo2 = { kind?: 'a', a: number } | { kind?: 'b' } | { kind?: never }; +>Foo2 : { kind?: "a" | undefined; a: number; } | { kind?: "b" | undefined; } | { kind?: undefined; } +>kind : "a" | undefined +>a : number +>kind : "b" | undefined +>kind : undefined + +function f2(foo: Foo2) { +>f2 : (foo: Foo2) => void +>foo : Foo2 + + if (foo.kind === 'a') { +>foo.kind === 'a' : boolean +>foo.kind : "a" | "b" | undefined +>foo : Foo2 +>kind : "a" | "b" | undefined +>'a' : "a" + + foo.a; +>foo.a : number +>foo : { kind?: "a" | undefined; a: number; } +>a : number + } +} + +// Repro from #50716 + +export interface GatewayPayloadStructure { + op: O +>op : O + + d: D +>d : D + + t?: T +>t : T | undefined + + s?: number +>s : number | undefined +} + +export type GatewayPayload = { +>GatewayPayload : GatewayPayloadStructure | GatewayPayloadStructure | GatewayPayloadStructure | GatewayPayloadStructure | GatewayPayloadStructure | GatewayPayloadStructure | GatewayPayloadStructure | GatewayPayloadStructure | GatewayPayloadStructure | GatewayPayloadStructure | GatewayPayloadStructure | GatewayPayloadStructure | GatewayPayloadStructure + + [O in GatewayOpcode]: O extends GatewayOpcode.DISPATCH +>GatewayOpcode : any + + ? { + [T in keyof GatewayEvents]: GatewayPayloadStructure +>GatewayOpcode : any + + }[keyof GatewayEvents] + : GatewayPayloadStructure +}[GatewayOpcode] + +export interface GatewayParams { + [GatewayOpcode.HELLO]: { b: 1 } +>[GatewayOpcode.HELLO] : { b: 1; } +>GatewayOpcode.HELLO : GatewayOpcode.HELLO +>GatewayOpcode : typeof GatewayOpcode +>HELLO : GatewayOpcode.HELLO +>b : 1 +} + +export enum GatewayOpcode { +>GatewayOpcode : GatewayOpcode + + DISPATCH = 0, +>DISPATCH : GatewayOpcode.DISPATCH +>0 : 0 + + HEARTBEAT = 1, +>HEARTBEAT : GatewayOpcode.HEARTBEAT +>1 : 1 + + IDENTIFY = 2, +>IDENTIFY : GatewayOpcode.IDENTIFY +>2 : 2 + + PRESENCE_UPDATE = 3, +>PRESENCE_UPDATE : GatewayOpcode.PRESENCE_UPDATE +>3 : 3 + + VOICE_STATE_UPDATE = 4, +>VOICE_STATE_UPDATE : GatewayOpcode.VOICE_STATE_UPDATE +>4 : 4 + + RESUME = 6, +>RESUME : GatewayOpcode.RESUME +>6 : 6 + + RECONNECT = 7, +>RECONNECT : GatewayOpcode.RECONNECT +>7 : 7 + + REQUEST_GUILD_MEMBERS = 8, +>REQUEST_GUILD_MEMBERS : GatewayOpcode.REQUEST_GUILD_MEMBERS +>8 : 8 + + INVALID_SESSION = 9, +>INVALID_SESSION : GatewayOpcode.INVALID_SESSION +>9 : 9 + + HELLO = 10, +>HELLO : GatewayOpcode.HELLO +>10 : 10 + + HEARTBEAT_ACK = 11, +>HEARTBEAT_ACK : GatewayOpcode.HEARTBEAT_ACK +>11 : 11 +} + +export interface GatewayEvents { + MESSAGE_CREATE: { a: 1 } +>MESSAGE_CREATE : { a: 1; } +>a : 1 + + MESSAGE_UPDATE: { a: 2 } +>MESSAGE_UPDATE : { a: 2; } +>a : 2 + + MESSAGE_DELETE: { a: 3 } +>MESSAGE_DELETE : { a: 3; } +>a : 3 +} + +function assertMessage(event: { a: 1 }) { } +>assertMessage : (event: { a: 1;}) => void +>event : { a: 1; } +>a : 1 + +export async function adaptSession(input: GatewayPayload) { +>adaptSession : (input: GatewayPayload) => Promise +>input : GatewayPayload + + if (input.t === 'MESSAGE_CREATE') { +>input.t === 'MESSAGE_CREATE' : boolean +>input.t : "MESSAGE_CREATE" | "MESSAGE_UPDATE" | "MESSAGE_DELETE" | undefined +>input : GatewayPayload +>t : "MESSAGE_CREATE" | "MESSAGE_UPDATE" | "MESSAGE_DELETE" | undefined +>'MESSAGE_CREATE' : "MESSAGE_CREATE" + + assertMessage(input.d) +>assertMessage(input.d) : void +>assertMessage : (event: { a: 1; }) => void +>input.d : { a: 1; } +>input : GatewayPayloadStructure +>d : { a: 1; } + } +} + diff --git a/tests/cases/compiler/neverAsDiscriminantType.ts b/tests/cases/compiler/neverAsDiscriminantType.ts new file mode 100644 index 0000000000000..d152d296e72f7 --- /dev/null +++ b/tests/cases/compiler/neverAsDiscriminantType.ts @@ -0,0 +1,66 @@ +// @strict: true, false + +type Foo1 = { kind: 'a', a: number } | { kind: 'b' } | { kind: never }; + +function f1(foo: Foo1) { + if (foo.kind === 'a') { + foo.a; + } +} + +type Foo2 = { kind?: 'a', a: number } | { kind?: 'b' } | { kind?: never }; + +function f2(foo: Foo2) { + if (foo.kind === 'a') { + foo.a; + } +} + +// Repro from #50716 + +export interface GatewayPayloadStructure { + op: O + d: D + t?: T + s?: number +} + +export type GatewayPayload = { + [O in GatewayOpcode]: O extends GatewayOpcode.DISPATCH + ? { + [T in keyof GatewayEvents]: GatewayPayloadStructure + }[keyof GatewayEvents] + : GatewayPayloadStructure +}[GatewayOpcode] + +export interface GatewayParams { + [GatewayOpcode.HELLO]: { b: 1 } +} + +export enum GatewayOpcode { + DISPATCH = 0, + HEARTBEAT = 1, + IDENTIFY = 2, + PRESENCE_UPDATE = 3, + VOICE_STATE_UPDATE = 4, + RESUME = 6, + RECONNECT = 7, + REQUEST_GUILD_MEMBERS = 8, + INVALID_SESSION = 9, + HELLO = 10, + HEARTBEAT_ACK = 11, +} + +export interface GatewayEvents { + MESSAGE_CREATE: { a: 1 } + MESSAGE_UPDATE: { a: 2 } + MESSAGE_DELETE: { a: 3 } +} + +function assertMessage(event: { a: 1 }) { } + +export async function adaptSession(input: GatewayPayload) { + if (input.t === 'MESSAGE_CREATE') { + assertMessage(input.d) + } +}