How can I make TypeScript warn me when a type guard no longer matches its type?

3 weeks ago 15
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.

Like so:

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:

enter image description here

...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.

Dai's user avatar

7 Comments

actually i don't really understand why checking if a value is not here is not a good idea, but since it's creating a distraction from the real question i removed it from the original post

2026-02-19T16:18:16.17Z+00:00

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

ok, i get the idea, but imagine i have two types, one with 'age' and one without it. If I want to check if a value is of type "withAge", that's easy. But when i want to check if a value is of type "withoutAge", how can i do it then ?

2026-02-19T16:34:01.707Z+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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.

Read Entire Article