<story><title>TypeScript Tricks: Type Guards</title><url>https://www.matthewgerstman.com/ts-tricks-type-guards/</url></story><parent_chain></parent_chain><comment><author>peterkelly</author><text>Discriminated unions [1] are what you&amp;#x27;re looking for here. Contrary to what the article claims, the functions shown are &lt;i&gt;not&lt;/i&gt; 100% type safe, because if you define the following:&lt;p&gt;&lt;pre&gt;&lt;code&gt;    interface NotActuallyWizard extends Person {
        type: PersonType.Wizard;
        otherStuff: string;
    }
&lt;/code&gt;&lt;/pre&gt;
and then write:&lt;p&gt;&lt;pre&gt;&lt;code&gt;    const JohnSmith: NotActuallyWizard = {
        type: PersonType.Wizard,
        name: &amp;#x27;John Smith&amp;#x27;,
        otherStuff: &amp;#x27;whatever&amp;#x27;,
    };

    getSpellsForPerson(JohnSmith);
&lt;/code&gt;&lt;/pre&gt;
it will pass the type checker (isWizard returns true because it doesn&amp;#x27;t take into account the possibility that &lt;i&gt;another&lt;/i&gt; interface may have a &amp;#x27;type&amp;#x27; property of PersonType.Wizard) but the code will fail at runtime.&lt;p&gt;Instead, you should define the interfaces as follows:&lt;p&gt;&lt;pre&gt;&lt;code&gt;    interface PersonBase {
        name: string;
    }

    interface Wizard extends PersonBase {
        type: &amp;#x27;Wizard&amp;#x27;;
        spells: string[];
    }

    interface Muggle extends PersonBase {
        type: &amp;#x27;Muggle&amp;#x27;;
        dursley: boolean;
    }

    type Person = Wizard | Muggle;
&lt;/code&gt;&lt;/pre&gt;
then replace the type guards with:&lt;p&gt;&lt;pre&gt;&lt;code&gt;    if (person.type !== &amp;#x27;Wizard&amp;#x27;) {
&lt;/code&gt;&lt;/pre&gt;
and&lt;p&gt;&lt;pre&gt;&lt;code&gt;    if (person.type !== &amp;#x27;Muggle&amp;#x27;) {
&lt;/code&gt;&lt;/pre&gt;
This will report an error for getSpellsForPerson(JohnSmith) because the compiler knows that (1) the only possibilities for Person are Wizard and Muggle, (2) both have type properties (3) the type properties have distinct literal values, and therefore (4) a Person with a type property of &amp;#x27;Wizard&amp;#x27; has must have a spells property and a Person with a type property of &amp;#x27;Muggle&amp;#x27; must have a dursley property.&lt;p&gt;As explained in [1], you can also take advantage of these with switch statements, and the compiler will do an exhaustiveness check so you catch any cases where you add a new type but forget to update one of your switches.&lt;p&gt;[1] &lt;a href=&quot;https:&amp;#x2F;&amp;#x2F;basarat.gitbooks.io&amp;#x2F;typescript&amp;#x2F;docs&amp;#x2F;types&amp;#x2F;discriminated-unions.html&quot; rel=&quot;nofollow&quot;&gt;https:&amp;#x2F;&amp;#x2F;basarat.gitbooks.io&amp;#x2F;typescript&amp;#x2F;docs&amp;#x2F;types&amp;#x2F;discrimina...&lt;/a&gt;</text></comment>
<story><title>TypeScript Tricks: Type Guards</title><url>https://www.matthewgerstman.com/ts-tricks-type-guards/</url></story><parent_chain></parent_chain><comment><author>city41</author><text>Be careful though, as they are not type safe in the sense the compiler completely trusts the type guard is implemented correctly.&lt;p&gt;In other words, TypeScript has no problem with this:&lt;p&gt;&lt;pre&gt;&lt;code&gt;    function isNumber(a: any): a is number {
        return typeof a === &amp;#x27;string&amp;#x27;;
    }
&lt;/code&gt;&lt;/pre&gt;
Type guards are usually simple functions, but I&amp;#x27;ve gotten them wrong before and only found out with a runtime exception.</text></comment>