forked from mystiq/hydrogen-web
Add type annotations to ObservableValue
This commit is contained in:
parent
a7360f409e
commit
ab6ce62551
1 changed files with 30 additions and 22 deletions
|
@ -18,18 +18,16 @@ import {AbortError} from "../utils/error.js";
|
||||||
import {BaseObservable} from "./BaseObservable";
|
import {BaseObservable} from "./BaseObservable";
|
||||||
|
|
||||||
// like an EventEmitter, but doesn't have an event type
|
// like an EventEmitter, but doesn't have an event type
|
||||||
export class BaseObservableValue extends BaseObservable {
|
export abstract class BaseObservableValue<T> extends BaseObservable<(value: T) => void> {
|
||||||
emit(argument) {
|
emit(argument: T) {
|
||||||
for (const h of this._handlers) {
|
for (const h of this._handlers) {
|
||||||
h(argument);
|
h(argument);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get() {
|
abstract get(): T;
|
||||||
throw new Error("unimplemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
waitFor(predicate) {
|
waitFor(predicate: (value: T) => boolean): IWaitHandle<T> {
|
||||||
if (predicate(this.get())) {
|
if (predicate(this.get())) {
|
||||||
return new ResolvedWaitForHandle(Promise.resolve(this.get()));
|
return new ResolvedWaitForHandle(Promise.resolve(this.get()));
|
||||||
} else {
|
} else {
|
||||||
|
@ -38,8 +36,17 @@ export class BaseObservableValue extends BaseObservable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class WaitForHandle {
|
interface IWaitHandle<T> {
|
||||||
constructor(observable, predicate) {
|
promise: Promise<T>;
|
||||||
|
dispose(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
class WaitForHandle<T> implements IWaitHandle<T> {
|
||||||
|
private _promise: Promise<T>
|
||||||
|
private _reject: ((reason?: any) => void) | null;
|
||||||
|
private _subscription: (() => void) | null;
|
||||||
|
|
||||||
|
constructor(observable: BaseObservableValue<T>, predicate: (value: T) => boolean) {
|
||||||
this._promise = new Promise((resolve, reject) => {
|
this._promise = new Promise((resolve, reject) => {
|
||||||
this._reject = reject;
|
this._reject = reject;
|
||||||
this._subscription = observable.subscribe(v => {
|
this._subscription = observable.subscribe(v => {
|
||||||
|
@ -52,7 +59,7 @@ class WaitForHandle {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
get promise() {
|
get promise(): Promise<T> {
|
||||||
return this._promise;
|
return this._promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,25 +75,24 @@ class WaitForHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ResolvedWaitForHandle {
|
class ResolvedWaitForHandle<T> implements IWaitHandle<T> {
|
||||||
constructor(promise) {
|
constructor(public promise: Promise<T>) {}
|
||||||
this.promise = promise;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispose() {}
|
dispose() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ObservableValue extends BaseObservableValue {
|
export class ObservableValue<T> extends BaseObservableValue<T> {
|
||||||
constructor(initialValue) {
|
private _value: T;
|
||||||
|
|
||||||
|
constructor(initialValue: T) {
|
||||||
super();
|
super();
|
||||||
this._value = initialValue;
|
this._value = initialValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
get() {
|
get(): T {
|
||||||
return this._value;
|
return this._value;
|
||||||
}
|
}
|
||||||
|
|
||||||
set(value) {
|
set(value: T): void {
|
||||||
if (value !== this._value) {
|
if (value !== this._value) {
|
||||||
this._value = value;
|
this._value = value;
|
||||||
this.emit(this._value);
|
this.emit(this._value);
|
||||||
|
@ -94,8 +100,10 @@ export class ObservableValue extends BaseObservableValue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class RetainedObservableValue extends ObservableValue {
|
export class RetainedObservableValue<T> extends ObservableValue<T> {
|
||||||
constructor(initialValue, freeCallback) {
|
private _freeCallback: () => void;
|
||||||
|
|
||||||
|
constructor(initialValue: T, freeCallback: () => void) {
|
||||||
super(initialValue);
|
super(initialValue);
|
||||||
this._freeCallback = freeCallback;
|
this._freeCallback = freeCallback;
|
||||||
}
|
}
|
||||||
|
@ -109,7 +117,7 @@ export class RetainedObservableValue extends ObservableValue {
|
||||||
export function tests() {
|
export function tests() {
|
||||||
return {
|
return {
|
||||||
"set emits an update": assert => {
|
"set emits an update": assert => {
|
||||||
const a = new ObservableValue();
|
const a = new ObservableValue<number>(0);
|
||||||
let fired = false;
|
let fired = false;
|
||||||
const subscription = a.subscribe(v => {
|
const subscription = a.subscribe(v => {
|
||||||
fired = true;
|
fired = true;
|
||||||
|
@ -140,7 +148,7 @@ export function tests() {
|
||||||
assert.strictEqual(a.get(), 6);
|
assert.strictEqual(a.get(), 6);
|
||||||
},
|
},
|
||||||
"waitFor promise rejects when disposed": async assert => {
|
"waitFor promise rejects when disposed": async assert => {
|
||||||
const a = new ObservableValue();
|
const a = new ObservableValue<number>(0);
|
||||||
const handle = a.waitFor(() => false);
|
const handle = a.waitFor(() => false);
|
||||||
Promise.resolve().then(() => {
|
Promise.resolve().then(() => {
|
||||||
handle.dispose();
|
handle.dispose();
|
||||||
|
|
Loading…
Reference in a new issue