Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript type guard Oddity

I'm using a TypeScript type guard in a ternary operator within a loop and seeing a behavior I don't understand.

My interfaces

interface INamed {
    name: string;
}

interface IOtherNamed extends INamed {
    otherName: string;
}

My type guard

function isOther(obj: any): obj is IOtherNamed {
    ... // some check that returns boolean
}

General Usage Sample

var list: Array<{named: INamed}> = [];

for(let item of list) {
    var other: IOtherNamed = ...
}

Inside of my for .. of loop I am using my type guard to assign either my current item or null to a variable of IOtherNamed.

This doesn't work

// Compiler Error: INamed is not assignable to IOtherNamed
for(let item of list) {
    var other: IOtherNamed = isOther(item.named) ? item.named : null;
}

This does

for(let item of list) {
    var named: INamed = item.named;
    var other2: IOtherNamed = isOther(named) ? named : null;
}

My Questions

  1. Is this by design that one of these works while the other doesn't?
  2. If by design, what is the nuance here that determines when it works or not? In particular why does assigning my object to a new variable (without any type change) get rid of the compiler error?
like image 645
bingles Avatar asked Nov 02 '15 13:11

bingles


People also ask

What is type guard in TypeScript?

A type guard is a TypeScript technique used to get information about the type of a variable, usually within a conditional block. Type guards are regular functions that return a boolean, taking a type and telling TypeScript if it can be narrowed down to something more specific.

What is ?: In TypeScript?

What does ?: mean in TypeScript? Using a question mark followed by a colon ( ?: ) means a property is optional. That said, a property can either have a value based on the type defined or its value can be undefined .

How do you narrow down TypeScript?

The in operator narrowing JavaScript has an operator for determining if an object has a property with a name: the in operator. TypeScript takes this into account as a way to narrow down potential types. For example, with the code: "value" in x . where "value" is a string literal and x is a union type.

What is type alias in TypeScript?

In Typescript, Type aliases give a type a new name. They are similar to interfaces in that they can be used to name primitives and any other kinds that you'd have to define by hand otherwise. Aliasing doesn't truly create a new type; instead, it gives that type a new name.


1 Answers

Yes, this is by design for TypeScript < 2.0:

Note that type guards affect types of variables and parameters only and have no effect on members of objects such as properties.

— 4.20 from the language specification (PDF, page 83)

So the reason it works in the second scenario is because you have assigned the property to a variable and then type guarded that variable.

Update: As Alex pointed out, TypeScript 2.0 will support type guards on properties.

like image 154
David Sherret Avatar answered Nov 15 '22 08:11

David Sherret