¿Cómo puedo restringir el tipo de propiedad de una clase en expresiones condicionales con alias?
Breve : en un método de clase, quiero hacer una verificación de reducción de tipos como this._end === null && this._head === null , pero primero quiero asignar el resultado de esta verificación a una variable antes de usarlo en un tipo que reduce la cláusula if . No está funcionando como se esperaba.
No corto : digamos que tenemos una clase Queue :
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; } }Si escribe un cheque en la función de puesta en cola directamente en la condición if , entonces TypeScript entiende que this._end no es nulo :
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; }Pero el código resulta ser menos descriptivo.
Además, en general, debo decir que ambas propiedades de la clase pasaron la verificación nula . Específicamente: this._head y this._end .
Escribí el siguiente método:
type QueuePointerKeys = '_head' | '_end'; private _isQueueEmpty(): this is this & { [K in QueuePointerKeys]: null } { return this._end === null; }Y no funciona. Si lo pones en el método de puesta en cola , entonces:
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; } ¿Cómo uso un método de clase como _isQueueEmpty para reducir el tipo? Eso funciona de manera similar a this._end === null && this._head === null usado directamente como la condición de la declaración if ?
El análisis de flujo de control de condiciones con alias y discriminantes se agregó recientemente y tiene limitaciones, que incluyen:
La restricción a través de referencias indirectas ocurre solo cuando la expresión condicional o el acceso a la propiedad discriminante se declaran en una declaración de variable constante sin anotación de tipo, y la referencia que se reduce es una variable constante, una propiedad de solo lectura o un parámetro para el cual no hay asignaciones en el cuerpo de la función.
Dado que this._end no es una propiedad de solo lectura, no funcionará para usted. Confirmé que este es su problema al asignar this._end a una variable const local y luego usarla para la condición, así como la llamada setLink :
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; } }De hecho, hay un problema abierto que aborda su caso específico: el análisis de flujo de control de las condiciones con alias no puede restringir las propiedades del objeto #46412 , así como permitir que se usen propiedades que no son de solo lectura en expresiones condicionales con alias #44972 .
Esperemos que puedan encontrar soluciones para estos pronto 🤞🏾