TypeScript: deleting a prop doesn't invalidate the interface
TypeScript Version: 2.1? (Playground)
Code
interface Props {
foo: string;
bar: string;
}
const p: Props = {
foo: 'hello',
bar: 'world'
}
const say = (props: Props) => console.log(`${props.foo.length} ${props.bar.length}`);
say(p);
delete p.bar;
say(p); // works, but should throw
See here.
Expected behavior:
Don’t compile, because we delete bar from p.
Actual behavior:
Compiles. Resulting in a runtime error: Uncaught TypeError: Cannot read property 'length' of undefined.
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 25
- Comments: 33 (9 by maintainers)
for this case, with
--strictNullChecks:I do not think control flow analysis is the right tool here, but we could disallow deleting a property whose type does not include
undefined; treeing it the same way asp.bar = undefined;.No, they have different semantics.
TypeScript currently lets you delete properties from objects even if they are non-optional, and even if you have every kind of option on like
--strictNullChecks,--noImplicitAny, or whatever.I’d class that as a bug.
I think treating
delete p.barasp.bar = undefinedis the right approach since they both do the same thing.i agree. delete should no be allowed under
--stricitNullChecksif the property does not includeundefined(the type system does not make a distinction between properties that are optional and those that are possibly undefined).This behavior surprised me, too.
+1 I didn’t want to say just +1 but, I definitely think the only thing I can contribute to this is +1. I have already given it a thumbs up, but I have very little confidence that thumbs upping the OP does anything in the eyes of anyone in charge. Hence my extremely long explanation of why I am making a +1 post.
I ran into this today and was surprised:
This could be easily fixed like this:
That is if you know what you’re doing you’re welcome to shoot yourself in the foot. But by default, TypeScript should aim to prevent runtime errors, not tolerate some temporary untyped state of a variable.
The best way I found to remove a prop from the object and infer a new object type is to use es6 destruct and rest features:
But I agree delete on a non optional property should be forbidden.
Facebook’s Flow added checking of
deletestatements in v0.109.If such property isn’t optional I don’t think you should be able to delete it, if you need to change the value just assign the new value. Delete is “the same” of assign undefined to the property.
If I was using an IDE Id expect a wavy line under the argument of
printNumberl8. Not at l7 where the deletion is operated.Because this
should be allowed.
Another example:
http://www.typescriptlang.org/play/index.html#code/JYOwLgpgTgZghgYwgAgJIFkCeB5ARgKwgTGQG8AoZZANzgBsBXCARgC5kQGBbXaAbnIBfcuQQB7EAGcSXHASJh2GOYWLIAvGUo16TNsgCsQkQBMIdCJGSy8qsADpajFgNETJYi-bpiA5gAobeWJHXRYASj5kAHpo5AYQMxhQCBM3KU8Ibz9AlQVQ52YNdU0EpJSTSJi4sCgmciC7Ar0NeMSIZJBUqNjkABVMAAcUAHIyjoqR5GBJDjESOElJYF8QOFwLZDAxLaHRzh5oEfsgA
I’m really surprised this bug hasn’t been picked up in over 2 years. @ryanberckmans what feedback do you need for this issue?
To track effects of
deleteyou need to compile with--strictNullChecksand declare the property optional. Upon seeingdelete p.barthe control flow analyzer will then considerp.barto have the valueundefined.