ARTICLE AD BOX
Using : any will disable all type-checking on the associated object, therefore TypeScript's type predicates (they aren't called "type-guards" anymore) should use : unknown instead.
type User = { id : string; name: string; }; function isUser(obj: unknown): obj is User { const assumeUser = obj as User; return ( ( typeof assumeUser.id === "string" ) && ( typeof assumeUser.name === "string" ) && // ( typeof assumeUser.age === 'undefined' ) !( 'age' in assumeUser ) ); } // const u: User = { id: '007', name: 'James Government Bond' }; console.log( "isUser: %o", isUser( u ) );If I rename User's name property to realName then I get squiggles:
...but if I keep name but change it to number (instead of string) then the typeof operator you won't get an error or warning, so it's a half-victory here.
BTW, it's generally not a good idea to assert that an object does not contain some member-property or similar as this means your program violates the Liskov Substitution Principle.
...but your check that age does not exist is incompatible with JavaScript (and TypeScript's) subtyping semantics.
159k31 gold badges315 silver badges441 bronze badges
7 Comments
In semver terms, it changes a minor bump to a major: adding a property is normally not a breaking change. But including the point Dai made about the LSP the main thing is that it makes your code less flexible for no real benefit. How much work do you want to do to update every usage site when the change request comes in?
2026-02-19T16:29:57.973Z+00:00
"But when i want to check if a value is of type "withoutAge", how can i do it then?" - That's a trick question because the answer is: "you don't": there is no legitimate reason for a program to need to check for the non-existence of a JS object property - that's why I left the comment about X/Y Problems. (Whereas if you do think that you do actually need to, then I think your program is incorrectly-designed and needs rethinking).
2026-02-19T16:37:01.557Z+00:00
you might be right, but i actually find it difficult to answer your question about if it is an X/Y problem, since i'm not sure how to choose the perimeter of the context to give. At first glance, it seems legitimate to me that i want to be able to check if a user is of type A or B, and it can happen that the difference between both is just one field. If i wanted to avoid the check for an absence of field, i could have a global check for common fields, then a check for the extra field, and deduce the type according to the result of the second check, but i think this is the same thing
2026-02-19T16:46:38.557Z+00:00
TypeScript can make inferences about the type of an object when it fails a type guard. That is, if your type is WithAge | WithoutAge and you have a function hasAge(obj: Any): obj is WithAge and you have this if statement if (hasAge(obj)) { ... } else { ... }, then the compiler can infer that obj must be WithoutAge in the else branch. That is test for the more specific type, and if it fails then you have the more general type.
2026-02-19T19:20:42.507Z+00:00
@ Dunes, yes, that's what i was describing (i concede it was not clear :p), and i really don't see the difference. Instead of checking "(obj not has field)" i'm checking "!(obj has field)" (since an else statement is a not-if). It seems logically identical to me, so why the first would be bad practice and the other good practice ?
2026-02-19T21:54:24.99Z+00:00
Explore related questions
See similar questions with these tags.




