Skip to content

Commit 60963d7

Browse files
authoredSep 13, 2022
Discriminant of type never should never be matched (#50755)
* Discriminant of type 'never' should never be matched * Add tests
1 parent e37ea53 commit 60963d7

8 files changed

+1101
-1
lines changed
 

‎src/compiler/checker.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -25130,7 +25130,7 @@ namespace ts {
2513025130
const narrowedPropType = narrowType(propType);
2513125131
return filterType(type, t => {
2513225132
const discriminantType = getTypeOfPropertyOrIndexSignature(t, propName);
25133-
return !(narrowedPropType.flags & TypeFlags.Never) && areTypesComparable(narrowedPropType, discriminantType);
25133+
return !(discriminantType.flags & TypeFlags.Never) && !(narrowedPropType.flags & TypeFlags.Never) && areTypesComparable(narrowedPropType, discriminantType);
2513425134
});
2513525135
}
2513625136

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
//// [neverAsDiscriminantType.ts]
2+
type Foo1 = { kind: 'a', a: number } | { kind: 'b' } | { kind: never };
3+
4+
function f1(foo: Foo1) {
5+
if (foo.kind === 'a') {
6+
foo.a;
7+
}
8+
}
9+
10+
type Foo2 = { kind?: 'a', a: number } | { kind?: 'b' } | { kind?: never };
11+
12+
function f2(foo: Foo2) {
13+
if (foo.kind === 'a') {
14+
foo.a;
15+
}
16+
}
17+
18+
// Repro from #50716
19+
20+
export interface GatewayPayloadStructure<O extends GatewayOpcode, T extends keyof GatewayEvents, D> {
21+
op: O
22+
d: D
23+
t?: T
24+
s?: number
25+
}
26+
27+
export type GatewayPayload = {
28+
[O in GatewayOpcode]: O extends GatewayOpcode.DISPATCH
29+
? {
30+
[T in keyof GatewayEvents]: GatewayPayloadStructure<GatewayOpcode.DISPATCH, T, GatewayEvents[T]>
31+
}[keyof GatewayEvents]
32+
: GatewayPayloadStructure<O, never, O extends keyof GatewayParams ? GatewayParams[O] : never>
33+
}[GatewayOpcode]
34+
35+
export interface GatewayParams {
36+
[GatewayOpcode.HELLO]: { b: 1 }
37+
}
38+
39+
export enum GatewayOpcode {
40+
DISPATCH = 0,
41+
HEARTBEAT = 1,
42+
IDENTIFY = 2,
43+
PRESENCE_UPDATE = 3,
44+
VOICE_STATE_UPDATE = 4,
45+
RESUME = 6,
46+
RECONNECT = 7,
47+
REQUEST_GUILD_MEMBERS = 8,
48+
INVALID_SESSION = 9,
49+
HELLO = 10,
50+
HEARTBEAT_ACK = 11,
51+
}
52+
53+
export interface GatewayEvents {
54+
MESSAGE_CREATE: { a: 1 }
55+
MESSAGE_UPDATE: { a: 2 }
56+
MESSAGE_DELETE: { a: 3 }
57+
}
58+
59+
function assertMessage(event: { a: 1 }) { }
60+
61+
export async function adaptSession(input: GatewayPayload) {
62+
if (input.t === 'MESSAGE_CREATE') {
63+
assertMessage(input.d)
64+
}
65+
}
66+
67+
68+
//// [neverAsDiscriminantType.js]
69+
"use strict";
70+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
71+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
72+
return new (P || (P = Promise))(function (resolve, reject) {
73+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
74+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
75+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
76+
step((generator = generator.apply(thisArg, _arguments || [])).next());
77+
});
78+
};
79+
var __generator = (this && this.__generator) || function (thisArg, body) {
80+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
81+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
82+
function verb(n) { return function (v) { return step([n, v]); }; }
83+
function step(op) {
84+
if (f) throw new TypeError("Generator is already executing.");
85+
while (_) try {
86+
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;
87+
if (y = 0, t) op = [op[0] & 2, t.value];
88+
switch (op[0]) {
89+
case 0: case 1: t = op; break;
90+
case 4: _.label++; return { value: op[1], done: false };
91+
case 5: _.label++; y = op[1]; op = [0]; continue;
92+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
93+
default:
94+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
95+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
96+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
97+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
98+
if (t[2]) _.ops.pop();
99+
_.trys.pop(); continue;
100+
}
101+
op = body.call(thisArg, _);
102+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
103+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
104+
}
105+
};
106+
exports.__esModule = true;
107+
exports.adaptSession = exports.GatewayOpcode = void 0;
108+
function f1(foo) {
109+
if (foo.kind === 'a') {
110+
foo.a;
111+
}
112+
}
113+
function f2(foo) {
114+
if (foo.kind === 'a') {
115+
foo.a;
116+
}
117+
}
118+
var GatewayOpcode;
119+
(function (GatewayOpcode) {
120+
GatewayOpcode[GatewayOpcode["DISPATCH"] = 0] = "DISPATCH";
121+
GatewayOpcode[GatewayOpcode["HEARTBEAT"] = 1] = "HEARTBEAT";
122+
GatewayOpcode[GatewayOpcode["IDENTIFY"] = 2] = "IDENTIFY";
123+
GatewayOpcode[GatewayOpcode["PRESENCE_UPDATE"] = 3] = "PRESENCE_UPDATE";
124+
GatewayOpcode[GatewayOpcode["VOICE_STATE_UPDATE"] = 4] = "VOICE_STATE_UPDATE";
125+
GatewayOpcode[GatewayOpcode["RESUME"] = 6] = "RESUME";
126+
GatewayOpcode[GatewayOpcode["RECONNECT"] = 7] = "RECONNECT";
127+
GatewayOpcode[GatewayOpcode["REQUEST_GUILD_MEMBERS"] = 8] = "REQUEST_GUILD_MEMBERS";
128+
GatewayOpcode[GatewayOpcode["INVALID_SESSION"] = 9] = "INVALID_SESSION";
129+
GatewayOpcode[GatewayOpcode["HELLO"] = 10] = "HELLO";
130+
GatewayOpcode[GatewayOpcode["HEARTBEAT_ACK"] = 11] = "HEARTBEAT_ACK";
131+
})(GatewayOpcode = exports.GatewayOpcode || (exports.GatewayOpcode = {}));
132+
function assertMessage(event) { }
133+
function adaptSession(input) {
134+
return __awaiter(this, void 0, void 0, function () {
135+
return __generator(this, function (_a) {
136+
if (input.t === 'MESSAGE_CREATE') {
137+
assertMessage(input.d);
138+
}
139+
return [2 /*return*/];
140+
});
141+
});
142+
}
143+
exports.adaptSession = adaptSession;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
=== tests/cases/compiler/neverAsDiscriminantType.ts ===
2+
type Foo1 = { kind: 'a', a: number } | { kind: 'b' } | { kind: never };
3+
>Foo1 : Symbol(Foo1, Decl(neverAsDiscriminantType.ts, 0, 0))
4+
>kind : Symbol(kind, Decl(neverAsDiscriminantType.ts, 0, 13))
5+
>a : Symbol(a, Decl(neverAsDiscriminantType.ts, 0, 24))
6+
>kind : Symbol(kind, Decl(neverAsDiscriminantType.ts, 0, 40))
7+
>kind : Symbol(kind, Decl(neverAsDiscriminantType.ts, 0, 56))
8+
9+
function f1(foo: Foo1) {
10+
>f1 : Symbol(f1, Decl(neverAsDiscriminantType.ts, 0, 71))
11+
>foo : Symbol(foo, Decl(neverAsDiscriminantType.ts, 2, 12))
12+
>Foo1 : Symbol(Foo1, Decl(neverAsDiscriminantType.ts, 0, 0))
13+
14+
if (foo.kind === 'a') {
15+
>foo.kind : Symbol(kind, Decl(neverAsDiscriminantType.ts, 0, 13), Decl(neverAsDiscriminantType.ts, 0, 40), Decl(neverAsDiscriminantType.ts, 0, 56))
16+
>foo : Symbol(foo, Decl(neverAsDiscriminantType.ts, 2, 12))
17+
>kind : Symbol(kind, Decl(neverAsDiscriminantType.ts, 0, 13), Decl(neverAsDiscriminantType.ts, 0, 40), Decl(neverAsDiscriminantType.ts, 0, 56))
18+
19+
foo.a;
20+
>foo.a : Symbol(a, Decl(neverAsDiscriminantType.ts, 0, 24))
21+
>foo : Symbol(foo, Decl(neverAsDiscriminantType.ts, 2, 12))
22+
>a : Symbol(a, Decl(neverAsDiscriminantType.ts, 0, 24))
23+
}
24+
}
25+
26+
type Foo2 = { kind?: 'a', a: number } | { kind?: 'b' } | { kind?: never };
27+
>Foo2 : Symbol(Foo2, Decl(neverAsDiscriminantType.ts, 6, 1))
28+
>kind : Symbol(kind, Decl(neverAsDiscriminantType.ts, 8, 13))
29+
>a : Symbol(a, Decl(neverAsDiscriminantType.ts, 8, 25))
30+
>kind : Symbol(kind, Decl(neverAsDiscriminantType.ts, 8, 41))
31+
>kind : Symbol(kind, Decl(neverAsDiscriminantType.ts, 8, 58))
32+
33+
function f2(foo: Foo2) {
34+
>f2 : Symbol(f2, Decl(neverAsDiscriminantType.ts, 8, 74))
35+
>foo : Symbol(foo, Decl(neverAsDiscriminantType.ts, 10, 12))
36+
>Foo2 : Symbol(Foo2, Decl(neverAsDiscriminantType.ts, 6, 1))
37+
38+
if (foo.kind === 'a') {
39+
>foo.kind : Symbol(kind, Decl(neverAsDiscriminantType.ts, 8, 13), Decl(neverAsDiscriminantType.ts, 8, 41), Decl(neverAsDiscriminantType.ts, 8, 58))
40+
>foo : Symbol(foo, Decl(neverAsDiscriminantType.ts, 10, 12))
41+
>kind : Symbol(kind, Decl(neverAsDiscriminantType.ts, 8, 13), Decl(neverAsDiscriminantType.ts, 8, 41), Decl(neverAsDiscriminantType.ts, 8, 58))
42+
43+
foo.a;
44+
>foo.a : Symbol(a, Decl(neverAsDiscriminantType.ts, 8, 25))
45+
>foo : Symbol(foo, Decl(neverAsDiscriminantType.ts, 10, 12))
46+
>a : Symbol(a, Decl(neverAsDiscriminantType.ts, 8, 25))
47+
}
48+
}
49+
50+
// Repro from #50716
51+
52+
export interface GatewayPayloadStructure<O extends GatewayOpcode, T extends keyof GatewayEvents, D> {
53+
>GatewayPayloadStructure : Symbol(GatewayPayloadStructure, Decl(neverAsDiscriminantType.ts, 14, 1))
54+
>O : Symbol(O, Decl(neverAsDiscriminantType.ts, 18, 41))
55+
>GatewayOpcode : Symbol(GatewayOpcode, Decl(neverAsDiscriminantType.ts, 35, 1))
56+
>T : Symbol(T, Decl(neverAsDiscriminantType.ts, 18, 65))
57+
>GatewayEvents : Symbol(GatewayEvents, Decl(neverAsDiscriminantType.ts, 49, 1))
58+
>D : Symbol(D, Decl(neverAsDiscriminantType.ts, 18, 96))
59+
60+
op: O
61+
>op : Symbol(GatewayPayloadStructure.op, Decl(neverAsDiscriminantType.ts, 18, 101))
62+
>O : Symbol(O, Decl(neverAsDiscriminantType.ts, 18, 41))
63+
64+
d: D
65+
>d : Symbol(GatewayPayloadStructure.d, Decl(neverAsDiscriminantType.ts, 19, 9))
66+
>D : Symbol(D, Decl(neverAsDiscriminantType.ts, 18, 96))
67+
68+
t?: T
69+
>t : Symbol(GatewayPayloadStructure.t, Decl(neverAsDiscriminantType.ts, 20, 8))
70+
>T : Symbol(T, Decl(neverAsDiscriminantType.ts, 18, 65))
71+
72+
s?: number
73+
>s : Symbol(GatewayPayloadStructure.s, Decl(neverAsDiscriminantType.ts, 21, 9))
74+
}
75+
76+
export type GatewayPayload = {
77+
>GatewayPayload : Symbol(GatewayPayload, Decl(neverAsDiscriminantType.ts, 23, 1))
78+
79+
[O in GatewayOpcode]: O extends GatewayOpcode.DISPATCH
80+
>O : Symbol(O, Decl(neverAsDiscriminantType.ts, 26, 5))
81+
>GatewayOpcode : Symbol(GatewayOpcode, Decl(neverAsDiscriminantType.ts, 35, 1))
82+
>O : Symbol(O, Decl(neverAsDiscriminantType.ts, 26, 5))
83+
>GatewayOpcode : Symbol(GatewayOpcode, Decl(neverAsDiscriminantType.ts, 35, 1))
84+
>DISPATCH : Symbol(GatewayOpcode.DISPATCH, Decl(neverAsDiscriminantType.ts, 37, 27))
85+
86+
? {
87+
[T in keyof GatewayEvents]: GatewayPayloadStructure<GatewayOpcode.DISPATCH, T, GatewayEvents[T]>
88+
>T : Symbol(T, Decl(neverAsDiscriminantType.ts, 28, 9))
89+
>GatewayEvents : Symbol(GatewayEvents, Decl(neverAsDiscriminantType.ts, 49, 1))
90+
>GatewayPayloadStructure : Symbol(GatewayPayloadStructure, Decl(neverAsDiscriminantType.ts, 14, 1))
91+
>GatewayOpcode : Symbol(GatewayOpcode, Decl(neverAsDiscriminantType.ts, 35, 1))
92+
>DISPATCH : Symbol(GatewayOpcode.DISPATCH, Decl(neverAsDiscriminantType.ts, 37, 27))
93+
>T : Symbol(T, Decl(neverAsDiscriminantType.ts, 28, 9))
94+
>GatewayEvents : Symbol(GatewayEvents, Decl(neverAsDiscriminantType.ts, 49, 1))
95+
>T : Symbol(T, Decl(neverAsDiscriminantType.ts, 28, 9))
96+
97+
}[keyof GatewayEvents]
98+
>GatewayEvents : Symbol(GatewayEvents, Decl(neverAsDiscriminantType.ts, 49, 1))
99+
100+
: GatewayPayloadStructure<O, never, O extends keyof GatewayParams ? GatewayParams[O] : never>
101+
>GatewayPayloadStructure : Symbol(GatewayPayloadStructure, Decl(neverAsDiscriminantType.ts, 14, 1))
102+
>O : Symbol(O, Decl(neverAsDiscriminantType.ts, 26, 5))
103+
>O : Symbol(O, Decl(neverAsDiscriminantType.ts, 26, 5))
104+
>GatewayParams : Symbol(GatewayParams, Decl(neverAsDiscriminantType.ts, 31, 16))
105+
>GatewayParams : Symbol(GatewayParams, Decl(neverAsDiscriminantType.ts, 31, 16))
106+
>O : Symbol(O, Decl(neverAsDiscriminantType.ts, 26, 5))
107+
108+
}[GatewayOpcode]
109+
>GatewayOpcode : Symbol(GatewayOpcode, Decl(neverAsDiscriminantType.ts, 35, 1))
110+
111+
export interface GatewayParams {
112+
>GatewayParams : Symbol(GatewayParams, Decl(neverAsDiscriminantType.ts, 31, 16))
113+
114+
[GatewayOpcode.HELLO]: { b: 1 }
115+
>[GatewayOpcode.HELLO] : Symbol(GatewayParams[GatewayOpcode.HELLO], Decl(neverAsDiscriminantType.ts, 33, 32))
116+
>GatewayOpcode.HELLO : Symbol(GatewayOpcode.HELLO, Decl(neverAsDiscriminantType.ts, 46, 24))
117+
>GatewayOpcode : Symbol(GatewayOpcode, Decl(neverAsDiscriminantType.ts, 35, 1))
118+
>HELLO : Symbol(GatewayOpcode.HELLO, Decl(neverAsDiscriminantType.ts, 46, 24))
119+
>b : Symbol(b, Decl(neverAsDiscriminantType.ts, 34, 28))
120+
}
121+
122+
export enum GatewayOpcode {
123+
>GatewayOpcode : Symbol(GatewayOpcode, Decl(neverAsDiscriminantType.ts, 35, 1))
124+
125+
DISPATCH = 0,
126+
>DISPATCH : Symbol(GatewayOpcode.DISPATCH, Decl(neverAsDiscriminantType.ts, 37, 27))
127+
128+
HEARTBEAT = 1,
129+
>HEARTBEAT : Symbol(GatewayOpcode.HEARTBEAT, Decl(neverAsDiscriminantType.ts, 38, 17))
130+
131+
IDENTIFY = 2,
132+
>IDENTIFY : Symbol(GatewayOpcode.IDENTIFY, Decl(neverAsDiscriminantType.ts, 39, 18))
133+
134+
PRESENCE_UPDATE = 3,
135+
>PRESENCE_UPDATE : Symbol(GatewayOpcode.PRESENCE_UPDATE, Decl(neverAsDiscriminantType.ts, 40, 17))
136+
137+
VOICE_STATE_UPDATE = 4,
138+
>VOICE_STATE_UPDATE : Symbol(GatewayOpcode.VOICE_STATE_UPDATE, Decl(neverAsDiscriminantType.ts, 41, 24))
139+
140+
RESUME = 6,
141+
>RESUME : Symbol(GatewayOpcode.RESUME, Decl(neverAsDiscriminantType.ts, 42, 27))
142+
143+
RECONNECT = 7,
144+
>RECONNECT : Symbol(GatewayOpcode.RECONNECT, Decl(neverAsDiscriminantType.ts, 43, 15))
145+
146+
REQUEST_GUILD_MEMBERS = 8,
147+
>REQUEST_GUILD_MEMBERS : Symbol(GatewayOpcode.REQUEST_GUILD_MEMBERS, Decl(neverAsDiscriminantType.ts, 44, 18))
148+
149+
INVALID_SESSION = 9,
150+
>INVALID_SESSION : Symbol(GatewayOpcode.INVALID_SESSION, Decl(neverAsDiscriminantType.ts, 45, 30))
151+
152+
HELLO = 10,
153+
>HELLO : Symbol(GatewayOpcode.HELLO, Decl(neverAsDiscriminantType.ts, 46, 24))
154+
155+
HEARTBEAT_ACK = 11,
156+
>HEARTBEAT_ACK : Symbol(GatewayOpcode.HEARTBEAT_ACK, Decl(neverAsDiscriminantType.ts, 47, 15))
157+
}
158+
159+
export interface GatewayEvents {
160+
>GatewayEvents : Symbol(GatewayEvents, Decl(neverAsDiscriminantType.ts, 49, 1))
161+
162+
MESSAGE_CREATE: { a: 1 }
163+
>MESSAGE_CREATE : Symbol(GatewayEvents.MESSAGE_CREATE, Decl(neverAsDiscriminantType.ts, 51, 32))
164+
>a : Symbol(a, Decl(neverAsDiscriminantType.ts, 52, 21))
165+
166+
MESSAGE_UPDATE: { a: 2 }
167+
>MESSAGE_UPDATE : Symbol(GatewayEvents.MESSAGE_UPDATE, Decl(neverAsDiscriminantType.ts, 52, 28))
168+
>a : Symbol(a, Decl(neverAsDiscriminantType.ts, 53, 21))
169+
170+
MESSAGE_DELETE: { a: 3 }
171+
>MESSAGE_DELETE : Symbol(GatewayEvents.MESSAGE_DELETE, Decl(neverAsDiscriminantType.ts, 53, 28))
172+
>a : Symbol(a, Decl(neverAsDiscriminantType.ts, 54, 21))
173+
}
174+
175+
function assertMessage(event: { a: 1 }) { }
176+
>assertMessage : Symbol(assertMessage, Decl(neverAsDiscriminantType.ts, 55, 1))
177+
>event : Symbol(event, Decl(neverAsDiscriminantType.ts, 57, 23))
178+
>a : Symbol(a, Decl(neverAsDiscriminantType.ts, 57, 31))
179+
180+
export async function adaptSession(input: GatewayPayload) {
181+
>adaptSession : Symbol(adaptSession, Decl(neverAsDiscriminantType.ts, 57, 43))
182+
>input : Symbol(input, Decl(neverAsDiscriminantType.ts, 59, 35))
183+
>GatewayPayload : Symbol(GatewayPayload, Decl(neverAsDiscriminantType.ts, 23, 1))
184+
185+
if (input.t === 'MESSAGE_CREATE') {
186+
>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)
187+
>input : Symbol(input, Decl(neverAsDiscriminantType.ts, 59, 35))
188+
>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)
189+
190+
assertMessage(input.d)
191+
>assertMessage : Symbol(assertMessage, Decl(neverAsDiscriminantType.ts, 55, 1))
192+
>input.d : Symbol(GatewayPayloadStructure.d, Decl(neverAsDiscriminantType.ts, 19, 9))
193+
>input : Symbol(input, Decl(neverAsDiscriminantType.ts, 59, 35))
194+
>d : Symbol(GatewayPayloadStructure.d, Decl(neverAsDiscriminantType.ts, 19, 9))
195+
}
196+
}
197+

0 commit comments

Comments
 (0)
Please sign in to comment.