Skip to content

Instantly share code, notes, and snippets.

@felixfbecker
Created November 30, 2017 04:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save felixfbecker/bc5a625c3e195132179199304e992476 to your computer and use it in GitHub Desktop.
Save felixfbecker/bc5a625c3e195132179199304e992476 to your computer and use it in GitHub Desktop.
Observable Array
import { Subject } from 'rxjs/Subject'
export interface Splice<T> {
/**
* The zero-based location in the array from which to start removing elements.
*/
start: number
/**
* The number of elements to remove.
*/
deleteCount: number
/**
* Elements to insert into the array in place of the deleted elements.
*/
items: ReadonlyArray<T>
}
const isReadonlyArray = (value: any): value is ReadonlyArray<any> =>
value && typeof value === 'object' && typeof value.length === 'number' && typeof value.slice === 'function'
export const isObservableArray = (value: any): value is ObservableArray<any> =>
value &&
typeof value === 'object' &&
typeof value.next === 'function' &&
typeof value.splice === 'function' &&
isReadonlyArray(value.elements)
export class ObservableArray<T> extends Subject<Splice<T>> {
public get elements(): ReadonlyArray<T> {
return this.mutatableElements
}
public set elements(elements: ReadonlyArray<T>) {
this.mutatableElements = Array.isArray(elements) ? elements : Array.from(elements)
this.next({ start: 0, deleteCount: Infinity, items: this.mutatableElements })
}
private mutatableElements: T[]
constructor(elements: T[]) {
super()
this.elements = elements
this.mutatableElements = elements
}
/**
* Removes elements from an array and, if necessary, inserts new elements in their place, returning the deleted elements.
* @param start The zero-based location in the array from which to start removing elements.
* @param deleteCount The number of elements to remove.
*/
public splice(start: number, deleteCount?: number): T[]
/**
* Removes elements from an array and, if necessary, inserts new elements in their place, returning the deleted elements.
* @param start The zero-based location in the array from which to start removing elements.
* @param deleteCount The number of elements to remove.
* @param items Elements to insert into the array in place of the deleted elements.
*/
public splice(start: number, deleteCount: number, ...items: T[]): T[]
public splice(start: number, deleteCount = 0, ...items: T[]): T[] {
const deletedElements = this.mutatableElements.splice(start, deleteCount, ...items)
this.next({ start, deleteCount, items })
return deletedElements
}
/**
* Removes the first element from an array and returns it.
*/
public shift(): T | undefined {
const value = this.mutatableElements.shift()
this.next({ start: 0, deleteCount: 1, items: [] })
return value
}
/**
* Inserts new elements at the start of an array.
* @param items Elements to insert at the start of the Array.
*/
public unshift(...items: T[]): number {
const newLength = this.mutatableElements.unshift(...items)
this.next({ start: 0, deleteCount: 0, items })
return newLength
}
/**
* Appends new elements to an array, and returns the new length of the array.
* @param items New elements of the Array.
*/
public push(...items: T[]): number {
const newLength = this.mutatableElements.push(...items)
this.next({ start: Infinity, deleteCount: 0, items })
return newLength
}
/**
* Removes the last element from an array and returns it.
*/
public pop(): T | undefined {
const element = this.mutatableElements.pop()
this.next({ start: -1, deleteCount: 1, items: [] })
return element
}
/**
* Reverses the elements in an Array.
*/
public reverse(): this {
this.mutatableElements.reverse()
this.next({ start: 0, deleteCount: Infinity, items: this.mutatableElements })
return this
}
/**
* Sorts an array.
* @param compareFn The name of the function used to determine the order of the elements. If omitted, the elements are sorted in ascending, ASCII character order.
*/
public sort(compareFn?: (a: T, b: T) => number): this {
this.mutatableElements.sort(compareFn)
this.next({ start: 0, deleteCount: Infinity, items: this.mutatableElements })
return this
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment