Open
Description
TypeScript Version: 2.2.0
// A *self-contained* demonstration of the problem follows...
type DeepReadonly<T> = {
readonly [K in keyof T]: DeepReadonly<T[K]>;
}
interface FieldBrand {
" do not use ": void;
}
type FieldId = number & FieldBrand;
interface DefOne {
field: string | FieldId;
kind: string;
}
interface DefTwo {
field?: undefined; // Allow discriminant checks on 'field'
value: string;
}
type Def = DefOne | DefTwo;
interface State {
a?: Def;
b?: Def;
}
type ROState = DeepReadonly<State>;
function lookupName(f: FieldId): string {
return "";
}
function remapFieldsToNames(channels: ROState): ROState {
const newState: State = {};
for (const k of Object.keys(channels)) {
const key = k as keyof ROState;
const ch = channels[key];
let replacement: ROState[typeof key] | undefined = undefined;
if (ch) {
if (ch.field) {
const f = ch.field;
if (typeof f === "number") {
f; // Should be FieldId or number, not never!
replacement = { ...ch, field: lookupName(f) };
}
else if (typeof f === "string") {
f; // correct
}
}
}
newState[k] = replacement || channels[k];
}
return newState;
}
Expected behavior:
There are no type errors in the above, and f
after the typeof f === "number"
check is either a number or FieldId
.
Actual behavior:
replacement = { ...ch, field: lookupName(f) };
has a type error and f
is of type never
.