Quero usar protetores de tipo para que hasNext possa filtrar os tipos.
type Queue1 = {
operation: 'move';
offset: number;
};
type Queue2 = {
operation: 'eat';
food: string;
};
type Queue3 = {
operation: 'run';
type: 'fast' | 'slow';
};
type ExampleQueue = Queue1 | Queue2 | Queue3;
export class ExampleEvent {
queue: Array<ExampleQueue>;
constructor(queue: Array<ExampleQueue> = []) {
this.queue = queue;
}
get event() {
return this.queue[0];
}
enqueue(value: ExampleQueue) {
this.queue.push(value);
}
dequeue() {
return this.queue.shift();
}
size() {
return this.queue.length;
}
hasNext<T extends ExampleQueue['operation'] = ExampleQueue['operation']>(
operation?: T
): this is ExampleEvent & { event: Extract<ExampleQueue, { operation: T }>; dequeue(): Extract<ExampleQueue, { operation: T }> } {
if (this.size() <= 0) return false;
return operation ? this.event.operation === operation : true;
}
}
Escrevi o código acima e usei-o conforme mostrado abaixo.
const event = new ExampleEvent();
if (event.hasNext('move')) {
event.event.offset // correct!
event.dequeue().offset // error!
}
Por que funciona para event.event.offset, mas não para event.dequeue().offset.type?
hasNext<T extends ExampleQueue['operation'] = ExampleQueue['operation']>(
operation?: T
): this is { event: Extract<ExampleQueue, { operation: T }>; dequeue(): Extract<ExampleQueue, { operation: T }> } & ExampleEvent {
if (this.size() <= 0) return false;
return operation ? this.event.operation === operation : true;
}
O que é incomum é que quando escrevo como acima, ele é validado corretamente. Não sei o que há de errado, é só que a ordem é invertida de cima.
Além disso, se eu escrever como abaixo, obtenho o resultado que desejo.
hasNext<T extends ExampleQueue['operation'] = ExampleQueue['operation']>(
operation?: T
): this is Omit<ExampleEvent, 'event' | 'dequeue'> & { event: Extract<ExampleQueue, { operation: T }>; dequeue(): Extract<ExampleQueue, { operation: T }> } {
if (this.size() <= 0) return false;
return operation ? this.event.operation === operation : true;
}