-
-
Notifications
You must be signed in to change notification settings - Fork 137
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Idea: install
helper
#128
Comments
Would the primary use of the installation helper be to make extras easier to implement for library consumers? If so, would it make sense for the helper to be attached to the extra? import xs from 'xstream';
import debounce from 'xstream/extra/debounce';
// install the extra
debounce.install();
// use the extra
xs.of( 'a' ).debounce(300); Alternatively, the function could be exported from core. import xs, { install } from 'xstream';
import debounce from 'xstream/extra/debounce';
// install the extra
install( debounce );
// use the extra
xs.of( 'a' ).debounce(300); The former doesn't lend itself to customization (pass your own operators to install). The latter does, and for that reason we'd need to do some name/symbol checking. import xs, { install } from 'xstream';
function mapTo( ) { return 1; }
// install the extra
install( mapTo ); // throw here? do nothing?
// okay, it threw. let's give it a name that it likes
function debounce( ) { return 1; }
install( debounce ); // what now? |
That's interesting, but ...
I prefer this option, because
And
I think it should do nothing. If we put install in core, it has to be super super small and simple. People doing One thing I haven't considered is how to support TypeScript. I wish there would be a way, but I'm afraid there won't be. :/ By the way, perhaps |
What is about typings? |
I think I found a way, based on official docs using "interface merging" and mixins:
Example: // The Stream interface and core implementation
export interface Stream {
map(fn: Function): Stream
}
export class Impl {
map(fn: Function): Stream {
// ...
}
}
export function create(producer: object): Stream {
return new Impl()
} // debounce extra
import { Impl } from './stream'
import { applyMixin } from './mixin'
// Define the partial interface
declare module './stream' {
interface Stream {
debounce(time: number): Stream
}
}
// Partial implementation (aka Mixin)
class Debounceable {
debounce(time: number): Debounceable {
return null
}
}
// Modify Impl prototype
applyMixin(Impl, [Debounceable]) // Mixin helper, but could be replaced with direct prototype manipulation
export function applyMixin(derivedCtor: any, baseCtors: any[]) {
baseCtors.forEach(baseCtor => {
Object.getOwnPropertyNames(baseCtor).forEach(name => {
derivedCtor.prototype[name] = baseCtor.prototype[name]
})
})
} Usage: import {Stream, create} from './stream'
var s = create(null)
s.map // OK
s.debounce // Error, Stream does not have "debounce"
// ...
import './debounce'
s.debounce // OK P.S.: I'm not sure how the MemoryStream fits here. |
It is enough to add in each extra operator module: declare module '../index' {
interface Stream<T> {
dropRepeats<T>(isEqual?: ((x: T, y: T) => boolean) | undefined): Stream<T>
}
}
Stream.prototype.dropRepeats = function (isEqual: any): any {
return this.compose(dropRepeast(isEqual))
} There is small consistency problem with interface merging that it will available even if one doesn't import the extra operator in a particular module. One just has to have it imported in a project scope somewhere, and merged interface will be available all over the place. Though this is how it works, and probably should work this way. |
I've created a PR #227 |
@whitecolor I just saw your PR #227, thanks. The As the latest discussion in #224, the plan is to keep the current folder structure, keep |
Have made a package xstream-extra for this. |
I think this issue won't happen. |
install(debounce)
would monkey patch Stream so you could doa$.debounce(300)
.The text was updated successfully, but these errors were encountered: