left click
left click

Reputation: 894

How to narrow a type using typeof keyword?

interface Students {
    [key:string]: (Student | undefined);
}

interface Student {
    age: string;
}

function something (students:Students, student_name:string) {
    let student:Student;

    if (typeof students[student_name] !== 'undefined')
        student = students[student_name]; // Type 'Student | undefined' is not assignable to type 'Student'.
    else
        return;
}

I often face that situation. Of course, I can use as Student. But, I wanna know if there's a better way.

Upvotes: 1

Views: 54

Answers (2)

jcalz
jcalz

Reputation: 327634

Usually TypeScript will use control-flow analysis to automatically narrow the type of a value once you have done a check on it. But the problem you're running into is the fact that this narrowing does not happen with bracket-style property accesses (see microsoft/TypeScript#10530) like students[student_name]. It was addressed for literal index types (see microsoft/TypeScript#26424) such as students["Alice"], equivalent to students.Alice... but to make it work with string would apparently degrade the compiler performance too much.

The workaround here is to perform the index access just once, and assign the result to a new variable. Then when you check that variable, the control flow analysis should narrow as you want:

function something(students: Students, student_name: string) {      
  let student: Student;      
  const maybeStudent = students[student_name]; // Student | undefined
  if (typeof maybeStudent !== 'undefined')
    student = maybeStudent; // okay, maybeStudent narrowed to Student in check
  else
    return;
}

Playground link to code

Upvotes: 3

Related Questions