diff --git a/api_guard/dist/types/index.d.ts b/api_guard/dist/types/index.d.ts index 7564d3c7f3..28db26d0af 100644 --- a/api_guard/dist/types/index.d.ts +++ b/api_guard/dist/types/index.d.ts @@ -159,6 +159,8 @@ export interface ErrorObserver { export declare type FactoryOrValue = T | (() => T); +export declare type Falsy = null | undefined | false | 0 | -0 | 0n | ''; + export declare function firstValueFrom(source: Observable): Promise; export declare function forkJoin(sources: []): Observable; @@ -371,9 +373,7 @@ export declare function of(a: T, b: T2, c: T3 export declare function of(): Observable; export declare function of(): Observable; export declare function of(value: T): Observable; -export declare function of(value1: T, value2: U): Observable; -export declare function of(value1: T, value2: U, value3: V): Observable; -export declare function of>(...args: A): Observable>; +export declare function of(...args: A): Observable>; export declare function onErrorResumeNext(): Observable; export declare function onErrorResumeNext>(arrayOfSources: O[]): Observable>; @@ -533,6 +533,8 @@ export interface TimestampProvider { now(): number; } +export declare type TruthyTypesOf = T extends Falsy ? never : T; + export interface UnaryFunction { (source: T): R; } @@ -549,7 +551,7 @@ export declare const UnsubscriptionError: UnsubscriptionErrorCtor; export declare function using(resourceFactory: () => Unsubscribable | void, observableFactory: (resource: Unsubscribable | void) => ObservableInput | void): Observable; -export declare type ValueFromArray = A extends Array ? T : never; +export declare type ValueFromArray = A extends Array ? T : never; export declare type ValueFromNotification = T extends { kind: 'N' | 'E' | 'C'; diff --git a/api_guard/dist/types/operators/index.d.ts b/api_guard/dist/types/operators/index.d.ts index 7d3937fcf4..cfe5bff3d4 100644 --- a/api_guard/dist/types/operators/index.d.ts +++ b/api_guard/dist/types/operators/index.d.ts @@ -96,6 +96,7 @@ export declare function endWith(v1: A, v2: B, v3: C, v4: D, v5 export declare function endWith(v1: A, v2: B, v3: C, v4: D, v5: E, v6: F, scheduler: SchedulerLike): OperatorFunction; export declare function endWith(...args: A): OperatorFunction>; +export declare function every(predicate: BooleanConstructor, thisArg?: any): OperatorFunction extends never ? false : boolean>; export declare function every(predicate: (value: T, index: number, source: Observable) => boolean, thisArg?: any): OperatorFunction; export declare function exhaust(): OperatorFunction, T>; @@ -108,19 +109,28 @@ export declare function exhaustMap(project: (value: T, index: number) = export declare function expand(project: (value: T, index: number) => ObservableInput, concurrent?: number, scheduler?: SchedulerLike): OperatorFunction; export declare function expand(project: (value: T, index: number) => ObservableInput, concurrent: number | undefined, scheduler: SchedulerLike): OperatorFunction; +export declare function filter(predicate: (value: T, index: number) => false, thisArg?: any): OperatorFunction; export declare function filter(predicate: (value: T, index: number) => value is S, thisArg?: any): OperatorFunction; -export declare function filter(predicate: BooleanConstructor): OperatorFunction; +export declare function filter(predicate: BooleanConstructor): OperatorFunction>; export declare function filter(predicate: (value: T, index: number) => boolean, thisArg?: any): MonoTypeOperatorFunction; export declare function finalize(callback: () => void): MonoTypeOperatorFunction; +export declare function find(predicate: BooleanConstructor): OperatorFunction>; export declare function find(predicate: (value: T, index: number, source: Observable) => value is S, thisArg?: any): OperatorFunction; export declare function find(predicate: (value: T, index: number, source: Observable) => boolean, thisArg?: any): OperatorFunction; +export declare function findIndex(predicate: (value: T, index: number, source: Observable) => false, thisArg?: any): OperatorFunction; +export declare function findIndex(predicate: BooleanConstructor, thisArg?: any): OperatorFunction; export declare function findIndex(predicate: (value: T, index: number, source: Observable) => boolean, thisArg?: any): OperatorFunction; export declare function first(predicate?: null, defaultValue?: D): OperatorFunction; +export declare function first(predicate: BooleanConstructor): OperatorFunction>; +export declare function first(predicate: BooleanConstructor, defaultValue: D): OperatorFunction | D>; export declare function first(predicate: (value: T, index: number, source: Observable) => value is S, defaultValue?: S): OperatorFunction; +export declare function first(predicate: (value: T, index: number, source: Observable) => value is S, defaultValue: D): OperatorFunction; +export declare function first(predicate: (value: T, index: number, source: Observable) => false, defaultValue: D): OperatorFunction; +export declare function first(predicate: (value: T, index: number, source: Observable) => false): OperatorFunction; export declare function first(predicate: (value: T, index: number, source: Observable) => boolean, defaultValue?: D): OperatorFunction; export declare const flatMap: typeof mergeMap; @@ -135,8 +145,12 @@ export declare function ignoreElements(): OperatorFunction; export declare function isEmpty(): OperatorFunction; +export declare function last(predicate: BooleanConstructor): OperatorFunction>; +export declare function last(predicate: BooleanConstructor, defaultValue: D): OperatorFunction | D>; export declare function last(predicate?: null, defaultValue?: D): OperatorFunction; export declare function last(predicate: (value: T, index: number, source: Observable) => value is S, defaultValue?: S): OperatorFunction; +export declare function last(predicate: (value: T, index: number, source: Observable) => false, defaultValue: D): OperatorFunction; +export declare function last(predicate: (value: T, index: number, source: Observable) => false): OperatorFunction; export declare function last(predicate: (value: T, index: number, source: Observable) => boolean, defaultValue?: D): OperatorFunction; export declare function map(project: (value: T, index: number) => R, thisArg?: any): OperatorFunction; @@ -240,6 +254,8 @@ export declare function share(): MonoTypeOperatorFunction; export declare function shareReplay(config: ShareReplayConfig): MonoTypeOperatorFunction; export declare function shareReplay(bufferSize?: number, windowTime?: number, scheduler?: SchedulerLike): MonoTypeOperatorFunction; +export declare function single(predicate: BooleanConstructor): OperatorFunction>; +export declare function single(predicate: (value: T, index: number, source: Observable) => false): OperatorFunction; export declare function single(predicate?: (value: T, index: number, source: Observable) => boolean): MonoTypeOperatorFunction; export declare function skip(count: number): MonoTypeOperatorFunction; @@ -248,6 +264,8 @@ export declare function skipLast(skipCount: number): MonoTypeOperatorFunction export declare function skipUntil(notifier: Observable): MonoTypeOperatorFunction; +export declare function skipWhile(predicate: BooleanConstructor): OperatorFunction extends never ? never : T>; +export declare function skipWhile(predicate: (value: T, index: number) => true): OperatorFunction; export declare function skipWhile(predicate: (value: T, index: number) => boolean): MonoTypeOperatorFunction; export declare function startWith(scheduler: SchedulerLike): MonoTypeOperatorFunction; @@ -279,6 +297,11 @@ export declare function takeLast(count: number): MonoTypeOperatorFunction; export declare function takeUntil(notifier: ObservableInput): MonoTypeOperatorFunction; +export declare function takeWhile(predicate: (value: T, index: number) => false, inclusive: true): MonoTypeOperatorFunction; +export declare function takeWhile(predicate: (value: T, index: number) => false, inclusive?: false): OperatorFunction; +export declare function takeWhile(predicate: BooleanConstructor): OperatorFunction extends never ? never : T>; +export declare function takeWhile(predicate: BooleanConstructor, inclusive: false): OperatorFunction extends never ? never : T>; +export declare function takeWhile(predicate: BooleanConstructor, inclusive: true): MonoTypeOperatorFunction; export declare function takeWhile(predicate: (value: T, index: number) => value is S): OperatorFunction; export declare function takeWhile(predicate: (value: T, index: number) => value is S, inclusive: false): OperatorFunction; export declare function takeWhile(predicate: (value: T, index: number) => boolean, inclusive?: boolean): MonoTypeOperatorFunction; diff --git a/spec-dtslint/observables/of-spec.ts b/spec-dtslint/observables/of-spec.ts index 66fcb9774b..c2fad5f300 100644 --- a/spec-dtslint/observables/of-spec.ts +++ b/spec-dtslint/observables/of-spec.ts @@ -136,4 +136,4 @@ it('should deprecate correctly', () => { of(a, b); // $ExpectNoDeprecation of(a, b, c); // $ExpectNoDeprecation of(a, b, c, d); // $ExpectNoDeprecation -}); +}); \ No newline at end of file diff --git a/spec-dtslint/operators/every-spec.ts b/spec-dtslint/operators/every-spec.ts index 562cfccf51..f313eb9f3d 100644 --- a/spec-dtslint/operators/every-spec.ts +++ b/spec-dtslint/operators/every-spec.ts @@ -36,3 +36,11 @@ it('should enforce index type of number', () => { it('should expect function parameter', () => { const a = of(1, 2, 3).pipe(every(9)); // $ExpectError }); + +it('should handle the Boolean constructor', () => { + const a = of(0 as const, '' as const, false as const, null, undefined, -0 as const, 0n as const).pipe(every(Boolean)); // $ExpectType Observable + const b = of(0 as const, '' as const, 'hi there' as const, false as const, null, undefined, -0 as const, 0n as const).pipe(every(Boolean)); // $ExpectType Observable + const c = of('test' as const, true as const, 1 as const, [], {}).pipe(every(Boolean)); // $ExpectType Observable + const d = of(NaN, NaN, NaN).pipe(every(Boolean)); // $ExpectType Observable + const e = of(0, 1, 0).pipe(every(Boolean)); // $ExpectType Observable +}) \ No newline at end of file diff --git a/spec-dtslint/operators/filter-spec.ts b/spec-dtslint/operators/filter-spec.ts index 55643c967e..b453f794b2 100644 --- a/spec-dtslint/operators/filter-spec.ts +++ b/spec-dtslint/operators/filter-spec.ts @@ -49,6 +49,12 @@ it('should support Boolean as a predicate', () => { const u = of(0 as const, -0 as const).pipe(filter(Boolean)); // $ExpectType Observable const v = of('' as const, "foo" as const, "bar" as const).pipe(filter(Boolean)); // $ExpectType Observable<"foo" | "bar"> const w = of('' as const).pipe(filter(Boolean)); // $ExpectType Observable + // Intentionally weird looking test... `false` is `boolean`, which is `true | false`. + const x = of(false, false, false, false).pipe(filter(Boolean)); // $ExpectType Observable +}); + +it('should narrow on always-false predicates', () => { + const o = of(1, 2, 3).pipe(filter(() => false)); // $ExpectType Observable }); // I've not been able to effect a failing dtslint test for this situation and a diff --git a/spec-dtslint/operators/find-spec.ts b/spec-dtslint/operators/find-spec.ts index ee8aa56d3a..36e986a9e3 100644 --- a/spec-dtslint/operators/find-spec.ts +++ b/spec-dtslint/operators/find-spec.ts @@ -24,3 +24,12 @@ it('should support a predicate that takes an index', () => { it('should support a predicate that takes an index and the source', () => { const o = of('foo').pipe(find((s, index, source) => true)); // $ExpectType Observable }); + +it('should support Boolean properly', () => { + const o1 = of('' as const).pipe(find(Boolean)); // $ExpectType Observable + const o2 = of('' as const, 'hi' as const).pipe(find(Boolean)); // $ExpectType Observable<"hi"> + const o3 = of('' as const, 0 as const, 'test' as const, 'what' as const).pipe(find(Boolean)); // $ExpectType Observable<"test" | "what"> + const o5 = of(false as const, null, undefined, '' as const, 0 as const, 0 as const).pipe(find(Boolean)); // $ExpectType Observable + // Intentionally weird looking: Because `Observable` is `Observable` and `true` is the truthy bit. + const o4 = of(false, false, false, false).pipe(find(Boolean)); // $ExpectType Observable +}); diff --git a/spec-dtslint/operators/findIndex-spec.ts b/spec-dtslint/operators/findIndex-spec.ts index 245acd164f..9e352fab7c 100644 --- a/spec-dtslint/operators/findIndex-spec.ts +++ b/spec-dtslint/operators/findIndex-spec.ts @@ -30,3 +30,12 @@ it('should enforce predicate types', () => { it('should enforce predicate return type', () => { const o = of('foo', 'bar', 'baz').pipe(findIndex(p => p)); // $ExpectError }); + +it('should support Boolean constructor', () => { + const a = of(0 as const, -0 as const, null, undefined, false as const, '' as const).pipe(findIndex(Boolean)); // $ExpectType Observable<-1> + const b = of(0 as const, -0 as const, null, 'hi there' as const, undefined, false as const, '' as const).pipe(findIndex(Boolean)); // $ExpectType Observable +}); + +it('should properly narrow an always false predicate', () => { + const a = of('foo', 'bar', 'baz').pipe(findIndex(() => false)); // $ExpectType Observable<-1> +}) \ No newline at end of file diff --git a/spec-dtslint/operators/first-spec.ts b/spec-dtslint/operators/first-spec.ts index 8f3aacd02f..1836b669ee 100644 --- a/spec-dtslint/operators/first-spec.ts +++ b/spec-dtslint/operators/first-spec.ts @@ -44,7 +44,7 @@ it('should support a user-defined type guard with an S default', () => { }); it('should widen a user-defined type guard with a non-S default', () => { - const o = of('foo').pipe(first(isFooBar, false)); // $ExpectType Observable + const o = of('foo').pipe(first(isFooBar, false)); // $ExpectType Observable }); it('should support a predicate with no default', () => { @@ -59,6 +59,10 @@ it('should support a predicate with a non-T default', () => { const o = of('foo').pipe(first(x => !!x, false)); // $ExpectType Observable }); -it('should default D to T with a predicate', () => { - const o = of('foo').pipe(first(x => !!x)); // $Observable -}); +it('should work properly with the Boolean constructor', () => { + const o1 = of('' as const).pipe(first(Boolean)); // $ExpectType Observable + const o2 = of('', 'hi').pipe(first(Boolean)); // $ExpectType Observable + const o3 = of('' as const, 'hi' as const).pipe(first(Boolean)); // $ExpectType Observable<"hi"> + const o4 = of(0 as const, 'hi' as const).pipe(first(Boolean)); // $ExpectType Observable<"hi"> + const o5 = of(0 as const, 'hi' as const, 'what' as const).pipe(first(Boolean)); // $ExpectType Observable<"hi" | "what"> +}) \ No newline at end of file diff --git a/spec-dtslint/operators/last-spec.ts b/spec-dtslint/operators/last-spec.ts index 817b0a840d..1d90c43159 100644 --- a/spec-dtslint/operators/last-spec.ts +++ b/spec-dtslint/operators/last-spec.ts @@ -60,5 +60,17 @@ it('should support a predicate with a non-T default', () => { }); it('should default D to T with a predicate', () => { - const o = of('foo').pipe(last(x => !!x)); // $Observable + const o = of('foo').pipe(last(x => !!x)); // $ExpectType Observable }); + +it('should handle predicates that always return false properly', () => { + const a = of('foo', 'bar').pipe(last(() => false as const)); // $ExpectType Observable + const b = of('foo', 'bar').pipe(last(() => false as const, 1337 as const)); // $ExpectType Observable<1337> +}); + +it('should handle Boolean constructor properly', () => { + const a = of(0 as const, -0 as const, null, undefined, false as const, '' as const, 0n as const).pipe(last(Boolean)); // $ExpectType Observable + const b = of(0 as const, -0 as const, null, undefined, false as const, '' as const, 0n as const).pipe(last(Boolean, 'test' as const)); // $ExpectType Observable<"test"> + const c = of(0 as const, -0 as const, null, 'hi' as const, undefined, false as const, '' as const, 0n as const).pipe(last(Boolean)); // $ExpectType Observable<"hi"> + const d = of(0 as const, -0 as const, null, 'hi' as const, undefined, false as const, '' as const, 0n as const).pipe(last(Boolean, 'test' as const)); // $ExpectType Observable<"test" | "hi"> +}) \ No newline at end of file diff --git a/spec-dtslint/operators/single-spec.ts b/spec-dtslint/operators/single-spec.ts index f8d0c5e17f..a05b03204c 100644 --- a/spec-dtslint/operators/single-spec.ts +++ b/spec-dtslint/operators/single-spec.ts @@ -32,3 +32,12 @@ it('should enforce index type', () => { it('should enforce source type', () => { const o = of('foo').pipe(single(((value, index, source: Observable) => value === 'foo'))); // $ExpectError }); + +it('should handle Boolean constructor properly', () => { + const a = of(null, undefined, 0 as const, -0 as const, 0n as const, '' as const).pipe(single(Boolean)); // $ExpectType Observable + const b = of(null, undefined, 0 as const, 'test' as const, -0 as const, 0n as const, '' as const).pipe(single(Boolean)); // $ExpectType Observable<"test"> +}); + +it('should handle predicates that always return false properly', () => { + const a = of(1, 2, 3, 4).pipe(single(() => false as const)); // $ExpectType Observable +}); \ No newline at end of file diff --git a/spec-dtslint/operators/skipWhile-spec.ts b/spec-dtslint/operators/skipWhile-spec.ts index 264a04cdfc..c352634e6b 100644 --- a/spec-dtslint/operators/skipWhile-spec.ts +++ b/spec-dtslint/operators/skipWhile-spec.ts @@ -21,3 +21,15 @@ it('should enforce predicate types', () => { it('should enforce predicate return type', () => { const o = of('foo', 'bar', 'baz').pipe(skipWhile(value => value)); // $ExpectError }); + +it('should handle Boolean constructor properly', () => { + // this one is a bit odd, but probably okay. + const a = of(null, undefined, 0 as const, -0 as const, '' as const, 0n as const, false as const).pipe(skipWhile(Boolean)); // $ExpectType Observable + const b = of(null, 0 as const, -0 as const, '' as const, 0n as const, false as const).pipe(skipWhile(Boolean)); // $ExpectType Observable + const c = of(1, 2, 3, '' as const, 0n as const, false as const, 4).pipe(skipWhile(Boolean)) // $ExpectType Observable + const d = of(true as const, 123 as const, 'HI' as const, {}, []).pipe(skipWhile(Boolean)); // $ExpectType Observable +}); + +it('should handle predicates that always return true properly', () => { + const a = of(1, 2, 3, 4).pipe(skipWhile(() => true as const)); // $ExpectType Observable +}); \ No newline at end of file diff --git a/spec-dtslint/operators/takeWhile-spec.ts b/spec-dtslint/operators/takeWhile-spec.ts index 3e34f249b3..74cd3ab1f0 100644 --- a/spec-dtslint/operators/takeWhile-spec.ts +++ b/spec-dtslint/operators/takeWhile-spec.ts @@ -16,3 +16,17 @@ it('should support a predicate', () => { it('should support a predicate with inclusive option', () => { const o = of('foo').pipe(takeWhile(s => true, true)); // $ExpectType Observable }); + +it('should properly support Boolean constructor', () => { + const a = of(false as const, 0 as const, -0 as const, 0n as const, '' as const, null, undefined).pipe(takeWhile(Boolean)); // $ExpectType Observable + // This is a weird one... but `Falsy` is equivalent here. I think this is TS trying to be "nice"? + const b = of(false as const, 0 as const, -0 as const, 0n as const, '' as const, null, undefined).pipe(takeWhile(Boolean, true)); // $ExpectType Observable + const c = of(false as const, 0 as const, 'hi' as const, -0 as const, 0n as const, '' as const, null, undefined).pipe(takeWhile(Boolean)); // $ExpectType Observable + const d = of(false as const, 0 as const, 'hi' as const, -0 as const, 0n as const, '' as const, null, undefined).pipe(takeWhile(Boolean, true)); // $ExpectType Observable + const e = of(1, ['hi'], false as const, 0 as const, -0 as const, 0n as const, '' as const, null, undefined).pipe(takeWhile(Boolean, true)); // $ExpectType Observable +}); + +it('should properly handle predicates that always return false', () => { + const a = of(1, 2, 3).pipe(takeWhile(() => false as const)); // $ExpectType Observable + const b = of(1, 2, 3).pipe(takeWhile(() => false as const, true)); // $ExpectType Observable +}); \ No newline at end of file diff --git a/src/internal/observable/of.ts b/src/internal/observable/of.ts index 8a23ee9154..6caf209d42 100644 --- a/src/internal/observable/of.ts +++ b/src/internal/observable/of.ts @@ -1,10 +1,10 @@ +/** @prettier */ import { SchedulerLike, ValueFromArray } from '../types'; import { internalFromArray } from './fromArray'; import { Observable } from '../Observable'; import { scheduleArray } from '../scheduled/scheduleArray'; import { popScheduler } from '../util/args'; -/* tslint:disable:max-line-length */ /** @deprecated The scheduler argument is deprecated, use scheduled. Details: https://rxjs.dev/deprecations/scheduler-argument */ export function of(scheduler: SchedulerLike): Observable; /** @deprecated The scheduler argument is deprecated, use scheduled. Details: https://rxjs.dev/deprecations/scheduler-argument */ @@ -18,26 +18,57 @@ export function of(a: T, b: T2, c: T3, d: T4, scheduler: Schedule /** @deprecated The scheduler argument is deprecated, use scheduled. Details: https://rxjs.dev/deprecations/scheduler-argument */ export function of(a: T, b: T2, c: T3, d: T4, e: T5, scheduler: SchedulerLike): Observable; /** @deprecated The scheduler argument is deprecated, use scheduled. Details: https://rxjs.dev/deprecations/scheduler-argument */ -export function of(a: T, b: T2, c: T3, d: T4, e: T5, f: T6, scheduler: SchedulerLike): Observable; +export function of( + a: T, + b: T2, + c: T3, + d: T4, + e: T5, + f: T6, + scheduler: SchedulerLike +): Observable; /** @deprecated The scheduler argument is deprecated, use scheduled. Details: https://rxjs.dev/deprecations/scheduler-argument */ -export function of(a: T, b: T2, c: T3, d: T4, e: T5, f: T6, g: T7, scheduler: SchedulerLike): - Observable; +export function of( + a: T, + b: T2, + c: T3, + d: T4, + e: T5, + f: T6, + g: T7, + scheduler: SchedulerLike +): Observable; /** @deprecated The scheduler argument is deprecated, use scheduled. Details: https://rxjs.dev/deprecations/scheduler-argument */ -export function of(a: T, b: T2, c: T3, d: T4, e: T5, f: T6, g: T7, h: T8, scheduler: SchedulerLike): - Observable; +export function of( + a: T, + b: T2, + c: T3, + d: T4, + e: T5, + f: T6, + g: T7, + h: T8, + scheduler: SchedulerLike +): Observable; /** @deprecated The scheduler argument is deprecated, use scheduled. Details: https://rxjs.dev/deprecations/scheduler-argument */ -export function of(a: T, b: T2, c: T3, d: T4, e: T5, f: T6, g: T7, h: T8, i: T9, scheduler: SchedulerLike): - Observable; +export function of( + a: T, + b: T2, + c: T3, + d: T4, + e: T5, + f: T6, + g: T7, + h: T8, + i: T9, + scheduler: SchedulerLike +): Observable; -// TODO(benlesh): Update the typings for this when we can switch to TS 3.x export function of(): Observable; /** @deprecated remove in v8. Do not use generic arguments directly, allow inference or cast with `as` */ export function of(): Observable; export function of(value: T): Observable; -export function of(value1: T, value2: U): Observable; -export function of(value1: T, value2: U, value3: V): Observable; -export function of>(...args: A): Observable>; -/* tslint:enable:max-line-length */ +export function of(...args: A): Observable>; /** * Converts the arguments to an observable sequence. diff --git a/src/internal/operators/every.ts b/src/internal/operators/every.ts index 59aa8d2a8a..138feed3d8 100644 --- a/src/internal/operators/every.ts +++ b/src/internal/operators/every.ts @@ -1,9 +1,18 @@ /** @prettier */ import { Observable } from '../Observable'; -import { OperatorFunction } from '../types'; +import { Falsy, OperatorFunction } from '../types'; import { operate } from '../util/lift'; import { OperatorSubscriber } from './OperatorSubscriber'; +export function every( + predicate: BooleanConstructor, + thisArg?: any +): OperatorFunction extends never ? false : boolean>; +export function every( + predicate: (value: T, index: number, source: Observable) => boolean, + thisArg?: any +): OperatorFunction; + /** * Returns an Observable that emits whether or not every item of the source satisfies the condition specified. * diff --git a/src/internal/operators/filter.ts b/src/internal/operators/filter.ts index 14118eb09e..3e7aaa3c9e 100644 --- a/src/internal/operators/filter.ts +++ b/src/internal/operators/filter.ts @@ -1,15 +1,12 @@ /** @prettier */ -import { OperatorFunction, MonoTypeOperatorFunction } from '../types'; +import { OperatorFunction, MonoTypeOperatorFunction, TruthyTypesOf } from '../types'; import { operate } from '../util/lift'; import { OperatorSubscriber } from './OperatorSubscriber'; -/* tslint:disable:max-line-length */ +export function filter(predicate: (value: T, index: number) => false, thisArg?: any): OperatorFunction; export function filter(predicate: (value: T, index: number) => value is S, thisArg?: any): OperatorFunction; -export function filter( - predicate: BooleanConstructor -): OperatorFunction; +export function filter(predicate: BooleanConstructor): OperatorFunction>; export function filter(predicate: (value: T, index: number) => boolean, thisArg?: any): MonoTypeOperatorFunction; -/* tslint:enable:max-line-length */ /** * Filter items emitted by the source Observable by only emitting those that diff --git a/src/internal/operators/find.ts b/src/internal/operators/find.ts index 180acff661..c96001638c 100644 --- a/src/internal/operators/find.ts +++ b/src/internal/operators/find.ts @@ -1,10 +1,11 @@ /** @prettier */ import { Observable } from '../Observable'; import { Subscriber } from '../Subscriber'; -import { OperatorFunction } from '../types'; +import { OperatorFunction, TruthyTypesOf } from '../types'; import { operate } from '../util/lift'; import { OperatorSubscriber } from './OperatorSubscriber'; +export function find(predicate: BooleanConstructor): OperatorFunction>; export function find( predicate: (value: T, index: number, source: Observable) => value is S, thisArg?: any diff --git a/src/internal/operators/findIndex.ts b/src/internal/operators/findIndex.ts index d0925c7e7f..339df4478d 100644 --- a/src/internal/operators/findIndex.ts +++ b/src/internal/operators/findIndex.ts @@ -1,8 +1,16 @@ /** @prettier */ import { Observable } from '../Observable'; -import { OperatorFunction } from '../types'; +import { Falsy, OperatorFunction } from '../types'; import { operate } from '../util/lift'; import { createFind } from './find'; + +export function findIndex(predicate: (value: T, index: number, source: Observable) => false, thisArg?: any): OperatorFunction; +export function findIndex(predicate: BooleanConstructor, thisArg?: any): OperatorFunction; +export function findIndex( + predicate: (value: T, index: number, source: Observable) => boolean, + thisArg?: any +): OperatorFunction; + /** * Emits only the index of the first value emitted by the source Observable that * meets some condition. diff --git a/src/internal/operators/first.ts b/src/internal/operators/first.ts index f278ee7c6b..2f09673cea 100644 --- a/src/internal/operators/first.ts +++ b/src/internal/operators/first.ts @@ -1,26 +1,30 @@ +/** @prettier */ import { Observable } from '../Observable'; import { EmptyError } from '../util/EmptyError'; -import { OperatorFunction } from '../types'; +import { OperatorFunction, TruthyTypesOf } from '../types'; import { filter } from './filter'; import { take } from './take'; import { defaultIfEmpty } from './defaultIfEmpty'; import { throwIfEmpty } from './throwIfEmpty'; import { identity } from '../util/identity'; -/* tslint:disable:max-line-length */ -export function first( - predicate?: null, - defaultValue?: D -): OperatorFunction; +export function first(predicate?: null, defaultValue?: D): OperatorFunction; +export function first(predicate: BooleanConstructor): OperatorFunction>; +export function first(predicate: BooleanConstructor, defaultValue: D): OperatorFunction | D>; export function first( predicate: (value: T, index: number, source: Observable) => value is S, defaultValue?: S ): OperatorFunction; +export function first( + predicate: (value: T, index: number, source: Observable) => value is S, + defaultValue: D +): OperatorFunction; +export function first(predicate: (value: T, index: number, source: Observable) => false, defaultValue: D): OperatorFunction; +export function first(predicate: (value: T, index: number, source: Observable) => false): OperatorFunction; export function first( predicate: (value: T, index: number, source: Observable) => boolean, defaultValue?: D ): OperatorFunction; -/* tslint:enable:max-line-length */ /** * Emits only the first value (or the first value that meets some condition) @@ -80,9 +84,10 @@ export function first( defaultValue?: D ): OperatorFunction { const hasDefaultValue = arguments.length >= 2; - return (source: Observable) => source.pipe( - predicate ? filter((v, i) => predicate(v, i, source)) : identity, - take(1), - hasDefaultValue ? defaultIfEmpty(defaultValue) : throwIfEmpty(() => new EmptyError()), - ); + return (source: Observable) => + source.pipe( + predicate ? filter((v, i) => predicate(v, i, source)) : identity, + take(1), + hasDefaultValue ? defaultIfEmpty(defaultValue) : throwIfEmpty(() => new EmptyError()) + ); } diff --git a/src/internal/operators/last.ts b/src/internal/operators/last.ts index faa7b3d4ec..05040ed37f 100644 --- a/src/internal/operators/last.ts +++ b/src/internal/operators/last.ts @@ -1,26 +1,26 @@ +/** @prettier */ import { Observable } from '../Observable'; import { EmptyError } from '../util/EmptyError'; -import { OperatorFunction } from '../types'; +import { OperatorFunction, TruthyTypesOf } from '../types'; import { filter } from './filter'; import { takeLast } from './takeLast'; import { throwIfEmpty } from './throwIfEmpty'; import { defaultIfEmpty } from './defaultIfEmpty'; import { identity } from '../util/identity'; -/* tslint:disable:max-line-length */ -export function last( - predicate?: null, - defaultValue?: D -): OperatorFunction; +export function last(predicate: BooleanConstructor): OperatorFunction>; +export function last(predicate: BooleanConstructor, defaultValue: D): OperatorFunction | D>; +export function last(predicate?: null, defaultValue?: D): OperatorFunction; export function last( predicate: (value: T, index: number, source: Observable) => value is S, defaultValue?: S ): OperatorFunction; +export function last(predicate: (value: T, index: number, source: Observable) => false, defaultValue: D): OperatorFunction; +export function last(predicate: (value: T, index: number, source: Observable) => false): OperatorFunction; export function last( predicate: (value: T, index: number, source: Observable) => boolean, defaultValue?: D ): OperatorFunction; -/* tslint:enable:max-line-length */ /** * Returns an Observable that emits only the last item emitted by the source Observable. @@ -29,34 +29,34 @@ export function last( * from the source Observable that satisfies the predicate. * * ![](last.png) - * + * * It will throw an error if the source completes without notification or one that matches the predicate. It - * returns the last value or if a predicate is provided last value that matches the predicate. It returns the + * returns the last value or if a predicate is provided last value that matches the predicate. It returns the * given default value if no notification is emitted or matches the predicate. - * + * * ## Example * Last alphabet from the sequence. * ```ts * import { from } from 'rxjs'; * import { last } from 'rxjs/operators'; - * + * * const source = from(['x', 'y', 'z']); * const example = source.pipe(last()); * //output: "Last alphabet: z" * example.subscribe(val => console.log(`Last alphabet: ${val}`)); * ``` - * + * * Default value when the value in the predicate is not matched. * ```ts * import { from } from 'rxjs'; * import { last } from 'rxjs/operators'; - * + * * const source = from(['x', 'y', 'z']); * const example = source.pipe(last(char => char === 'a','not exist')); * //output: "'a' is not exist." * example.subscribe(val => console.log(`'a' is ${val}.`)); * ``` - * + * * @see {@link skip} * @see {@link skipUntil} * @see {@link skipLast} @@ -76,9 +76,10 @@ export function last( defaultValue?: D ): OperatorFunction { const hasDefaultValue = arguments.length >= 2; - return (source: Observable) => source.pipe( - predicate ? filter((v, i) => predicate(v, i, source)) : identity, - takeLast(1), - hasDefaultValue ? defaultIfEmpty(defaultValue) : throwIfEmpty(() => new EmptyError()), - ); + return (source: Observable) => + source.pipe( + predicate ? filter((v, i) => predicate(v, i, source)) : identity, + takeLast(1), + hasDefaultValue ? defaultIfEmpty(defaultValue) : throwIfEmpty(() => new EmptyError()) + ); } diff --git a/src/internal/operators/single.ts b/src/internal/operators/single.ts index 070226cf7e..897db2a9b1 100644 --- a/src/internal/operators/single.ts +++ b/src/internal/operators/single.ts @@ -1,12 +1,17 @@ +/** @prettier */ import { Observable } from '../Observable'; import { EmptyError } from '../util/EmptyError'; -import { MonoTypeOperatorFunction } from '../types'; +import { MonoTypeOperatorFunction, OperatorFunction, TruthyTypesOf } from '../types'; import { SequenceError } from '../util/SequenceError'; import { NotFoundError } from '../util/NotFoundError'; import { operate } from '../util/lift'; import { OperatorSubscriber } from './OperatorSubscriber'; +export function single(predicate: BooleanConstructor): OperatorFunction>; +export function single(predicate: (value: T, index: number, source: Observable) => false): OperatorFunction; +export function single(predicate?: (value: T, index: number, source: Observable) => boolean): MonoTypeOperatorFunction; + /** * Returns an observable that asserts that only one value is * emitted from the observable that matches the predicate. If no @@ -87,28 +92,33 @@ import { OperatorSubscriber } from './OperatorSubscriber'; * @return {Observable} An Observable that emits the single item emitted by the source Observable that matches * the predicate or `undefined` when no items match. */ -export function single( - predicate?: (value: T, index: number, source: Observable) => boolean -): MonoTypeOperatorFunction { +export function single(predicate?: (value: T, index: number, source: Observable) => boolean): MonoTypeOperatorFunction { return operate((source, subscriber) => { let hasValue = false; let singleValue: T; let seenValue = false; let index = 0; - source.subscribe(new OperatorSubscriber(subscriber, value => { - seenValue = true; - if (!predicate || predicate(value, index++, source)) { - hasValue && subscriber.error(new SequenceError('Too many matching values')); - hasValue = true; - singleValue = value; - } - }, undefined, () => { - if (hasValue) { - subscriber.next(singleValue); - subscriber.complete(); - } else { - subscriber.error(seenValue ? new NotFoundError('No matching values') : new EmptyError()) - } - })) + source.subscribe( + new OperatorSubscriber( + subscriber, + (value) => { + seenValue = true; + if (!predicate || predicate(value, index++, source)) { + hasValue && subscriber.error(new SequenceError('Too many matching values')); + hasValue = true; + singleValue = value; + } + }, + undefined, + () => { + if (hasValue) { + subscriber.next(singleValue); + subscriber.complete(); + } else { + subscriber.error(seenValue ? new NotFoundError('No matching values') : new EmptyError()); + } + } + ) + ); }); } diff --git a/src/internal/operators/skipWhile.ts b/src/internal/operators/skipWhile.ts index 39aea54ebf..57a5cf2726 100644 --- a/src/internal/operators/skipWhile.ts +++ b/src/internal/operators/skipWhile.ts @@ -1,8 +1,12 @@ /** @prettier */ -import { MonoTypeOperatorFunction } from '../types'; +import { Falsy, MonoTypeOperatorFunction, OperatorFunction } from '../types'; import { operate } from '../util/lift'; import { OperatorSubscriber } from './OperatorSubscriber'; +export function skipWhile(predicate: BooleanConstructor): OperatorFunction extends never ? never : T>; +export function skipWhile(predicate: (value: T, index: number) => true): OperatorFunction; +export function skipWhile(predicate: (value: T, index: number) => boolean): MonoTypeOperatorFunction; + /** * Returns an Observable that skips all items emitted by the source Observable as long as a specified condition holds * true, but emits all further source items as soon as the condition becomes false. diff --git a/src/internal/operators/takeWhile.ts b/src/internal/operators/takeWhile.ts index 2257ea5b2c..151eac4aaa 100644 --- a/src/internal/operators/takeWhile.ts +++ b/src/internal/operators/takeWhile.ts @@ -1,8 +1,16 @@ /** @prettier */ -import { OperatorFunction, MonoTypeOperatorFunction } from '../types'; +import { OperatorFunction, MonoTypeOperatorFunction, Falsy } from '../types'; import { operate } from '../util/lift'; import { OperatorSubscriber } from './OperatorSubscriber'; +export function takeWhile(predicate: (value: T, index: number) => false, inclusive: true): MonoTypeOperatorFunction; +export function takeWhile(predicate: (value: T, index: number) => false, inclusive?: false): OperatorFunction; +export function takeWhile(predicate: BooleanConstructor): OperatorFunction extends never ? never : T>; +export function takeWhile( + predicate: BooleanConstructor, + inclusive: false +): OperatorFunction extends never ? never : T>; +export function takeWhile(predicate: BooleanConstructor, inclusive: true): MonoTypeOperatorFunction; export function takeWhile(predicate: (value: T, index: number) => value is S): OperatorFunction; export function takeWhile(predicate: (value: T, index: number) => value is S, inclusive: false): OperatorFunction; export function takeWhile(predicate: (value: T, index: number) => boolean, inclusive?: boolean): MonoTypeOperatorFunction; diff --git a/src/internal/types.ts b/src/internal/types.ts index c1a086bfdb..f82b99f948 100644 --- a/src/internal/types.ts +++ b/src/internal/types.ts @@ -263,7 +263,7 @@ export type Tail = ((...args: X) => any) extends (arg: any, ... * If you have `T extends Array`, and pass a `string[]` to it, * `ValueFromArray` will return the actual type of `string`. */ -export type ValueFromArray = A extends Array ? T : never; +export type ValueFromArray = A extends Array ? T : never; /** * Gets the value type from an {@link ObservableNotification}, if possible. @@ -275,3 +275,12 @@ export type ValueFromNotification = T extends { kind: 'N' | 'E' | 'C' } : undefined : never : never; + +/** + * A simple type to represent a gamut of "falsy" values... with a notable exception: + * `NaN` is "falsy" however, it is not and cannot be typed via TypeScript. See + * comments here: https://github.com/microsoft/TypeScript/issues/28682#issuecomment-707142417 + */ +export type Falsy = null | undefined | false | 0 | -0 | 0n | ''; + +export type TruthyTypesOf = T extends Falsy ? never : T;