Closed
Description
Bug Report
🔎 Search Terms
type narrowing assertNever never unreachable
🕗 Version & Regression Information
- This changed between versions 4.7.4 and 4.8.x
⏯ Playground Link
Playground Link: Provided
💻 Code
enum PropertyType {
String = 'string',
Number = 'number',
Unknown = 'unknown',
}
interface Property<Type extends PropertyType, Value extends unknown = unknown> {
type: Type;
value: Value;
}
type StringProperty = Property<PropertyType.String, string>;
type NumberProperty = Property<PropertyType.Number, number>;
type UnknownProperty = Property<PropertyType.Unknown, unknown>;
type PropertyObject =
| StringProperty
| NumberProperty
| UnknownProperty
type PropertyObjectOrEmpty = PropertyObject | { type: PropertyType; value: undefined };
interface Edit<VT extends PropertyObject = PropertyObject> {
type: 'edit';
property: VT;
}
interface Add<VT extends PropertyObjectOrEmpty = PropertyObjectOrEmpty> {
type: 'add';
property: VT;
}
function assertNever(n: never): never {
throw new Error('nope');
}
function doStuff(action: Edit | Add) {
if (action.property.value == null) {
// do something
} else if (action.property.type === PropertyType.Unknown) {
// do something else
} else {
// this line is reachable, but compiles without error!
assertNever(action.property);
}
}
doStuff({
type: 'edit',
property: {
type: PropertyType.String,
value: 'hello, world'
}
})
Output
"use strict";
var PropertyType;
(function (PropertyType) {
PropertyType["String"] = "string";
PropertyType["Number"] = "number";
PropertyType["Unknown"] = "unknown";
})(PropertyType || (PropertyType = {}));
function assertNever(n) {
throw new Error('nope');
}
function doStuff(action) {
if (action.property.value == null) {
// do something
}
else if (action.property.type === PropertyType.Unknown) {
// do something else
}
else {
// this line is reachable, but compiles without error!
assertNever(action.property);
}
}
doStuff({
type: 'edit',
property: {
type: PropertyType.String,
value: 'hello, world'
}
});
Compiler Options
{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictPropertyInitialization": true,
"strictBindCallApply": true,
"noImplicitThis": true,
"noImplicitReturns": true,
"alwaysStrict": true,
"esModuleInterop": true,
"declaration": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"target": "ES2017",
"jsx": "react",
"module": "ESNext",
"moduleResolution": "node"
}
}
🙁 Actual behavior
Code compiles without error, but assertNever
is hit at runtime.
🙂 Expected behavior
Compilation error: the type of action.property
at the point it's passed to assertNever
is not never
. (4.7 does this.)