Description
Search Terms:
typescript unsafe Record unknown assignment interfaces all optional undefined sound type system
Code
I discovered the following code to be legal. It was pretty scary.
interface ObjWithPropFalsy {
prop?: false;
}
const a: Record<string, boolean> = { prop: true };
const b: ObjWithPropFalsy = a;
if (b.prop) { // b.prop is of type false | undefined, but its value is true
console.log("typing says it never happens") // <-- will print
} else {
console.log("typing says it always happens")
}
This is so dangerous for me* that I decided to propose a new eslint rule warning about it, but @bradzacher suggested I brought this issue to the TypeScript team. He also added the following example, which is even more intense because unknown
isn't really relevant here:
interface ObjWithPropFalsy {
prop?: false;
}
const a: Record<string, string> = { prop: 'str' };
const b: ObjWithPropFalsy = a;
type T = (typeof b)['prop']; // === false | undefined;
typeof a.prop === 'string' // runtime
Expected behavior:
Compilation error.
Actual behavior:
Compilation successful.
*(can explain the use-case that led to the discovery if it's relevant)
I understand this might be an inevitable design limitation coming from index signatures, so this might be closer to a feature request than a bug? If this is the case, sorry for the wrong labeling.