Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

202
Vistas
Why doesn't a type narrowing check of a class property not work when assigned to a variable (aliased conditions)?

How can I narrow the type of property of a class in an aliased conditional expressions?

Short: In a class method I want to do a type narrowing check such as this._end === null && this._head === null, but I want to first assign the result of this check to a variable before using it in a type narrowing if clause. It's not working as expected.

Not short: Let's say we have a Queue class:

class Queue {
  private _length: number = 0;
  private _head: Node | null = null;
  private _end: Node | null = null;

  public enqueue(node: Node): boolean {
    this._length += 1;

    const isQueueEmpty = this._end === null;
    if (isQueueEmpty) {
      this._head = node;
      this._end = node;
      return true;
    }

    this._end.setLink(node); // TypeScript doesn't understand that this._end passed the null check 
                             // in the if statement and writes that this._end can be null. 
    this._end = node;
    return true;
  }
}

If you write a check in the enqueue function directly in the if condition, then TypeScript understands that this._end is not null:

public enqueue(node: Node): boolean {
  this._length += 1;

  if (this._end === null) {
    this._head = node;
    this._end = node;
    return true;
  }

  this._end.setLink(node); // Now TypeScript understand that this._end passed the null check
  this._end = node;
  return true;
}

But the code turns out to be less descriptive.

Moreover, in general, I need to say that both properties of the class passed the null check. Specifically: this._head and this._end.

I wrote the following method:

type QueuePointerKeys = '_head' | '_end';

private _isQueueEmpty(): this is this & { [K in QueuePointerKeys]: null } {
  return this._end === null;
}

And it doesn't work. If you put it in the enqueue method, then:

public enqueue(node: Node): boolean {
  this._length += 1;

  if (this._isQueueEmpty()) {
    this._head = node;     // TypeScript writes that a variable of type null cannot be assigned the type Node
    this._end = node;      // TypeScript writes that a variable of type null cannot be assigned the type Node
    return true;
  }

  this._end.setLink(node); // TypeScript doesn't understand that this._end passed the null check
                           // in the if statement and writes that this._end can be null.
  this._end = node;
  return true;
}

How do I use a class method such as _isQueueEmpty for type narrowing? That works similarly to this._end === null && this._head === null used directly as the condition of the if statement?

about 4 years ago · Juan Pablo Isaza
1 Respuestas
Responde la pregunta

0

Control Flow Analysis of Aliased Conditions and Discriminants was only recently added, and it has limitations, including:

Narrowing through indirect references occurs only when the conditional expression or discriminant property access is declared in a const variable declaration with no type annotation, and the reference being narrowed is a const variable, a readonly property, or a parameter for which there are no assignments in the function body.

Since this._end is not a readonly property, it's not going to work for you. I confirmed that this is your problem by assigning this._end to a local const variable, and then using it for the condition as well as the setLink call:

interface Node {
  setLink(node: Node): void
}

class Queue {
  private _length: number = 0;
  private _head: Node | null = null;
  private _end: Node | null = null;

  public enqueue(node: Node): boolean {
    this._length += 1;

    const end = this._end
    const isQueueEmpty = end === null;

    if (isQueueEmpty) {
      this._head = node;
      this._end = node;
      return true;
    }

    end.setLink(node);
    this._end = node;
    return true;
  }

}

In fact, there is an open issue addressing your specific case: Control flow analysis of aliased conditions is not able to narrow object properties #46412, as well as Allow non-readonly properties to be used in aliased conditional expressions #44972.

Let's hope they can find solutions for these soonish 🤞🏾

about 4 years ago · Juan Pablo Isaza Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda