Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't TypeScript type guard 'in' narrows types to keyof types?

Consider this code:

const obj = {
    a: 1,
    b: 2
}

let possibleKey: string = 'a'

if (possibleKey in obj) console.log(obj[possibleKey])

When possibleKey in obj is true, we know that possibleKey has type keyof typeof obj, right? Why doesn't TypeScript type system detects that and narrows down string to that type? Instead, it says:

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ a: number; b: number; }'.
like image 587
André Willik Valenti Avatar asked Jan 07 '20 12:01

André Willik Valenti


People also ask

Is Keyof TypeScript?

keyof is a keyword in TypeScript which is used to extract the key type from an object type.

What is type narrowing in TypeScript?

TypeScript follows possible paths of execution that our programs can take to analyze the most specific possible type of a value at a given position. It looks at these special checks (called type guards) and assignments, and the process of refining types to more specific types than declared is called narrowing.

How do I compare types in TypeScript?

In Typescript, we have three ways to work with it using: typeof: the keyword helps to check values types, like boolean, string, number, etc. instanceof: the keyword to compare the object instance with a class constructor. type guards: The powerful way to check types using typescript feature language.


1 Answers

Per the docs:

For a n in x expression, where n is a string literal or string literal type and x is a union type, the “true” branch narrows to types which have an optional or required property n, and the “false” branch narrows to types which have an optional or missing property n.

In other words, n in x narrows x, not n, and only for string literals or string literal types in union types. For that expression to work, you'd have to give the compiler more information, e.g. using a type assertion:

if (possibleKey in obj) {
  console.log(obj[<keyof typeof obj>possibleKey]);
}
like image 171
jonrsharpe Avatar answered Nov 15 '22 06:11

jonrsharpe