Skip to content
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

fix: predicates that return any will now behave property in TS #5987

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions api_guard/dist/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,6 @@ export declare type Head<X extends readonly any[]> = ((...args: X) => any) exten

export declare function identity<T>(x: T): T;

export declare function iif<T>(condition: () => true, trueResult: ObservableInput<T>, falseResult: ObservableInput<any>): Observable<T>;
export declare function iif<F>(condition: () => false, trueResult: ObservableInput<any>, falseResult: ObservableInput<F>): Observable<F>;
export declare function iif<T, F>(condition: () => boolean, trueResult: ObservableInput<T>, falseResult: ObservableInput<F>): Observable<T | F>;

export interface InteropObservable<T> {
Expand Down
7 changes: 0 additions & 7 deletions api_guard/dist/types/operators/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,6 @@ export declare function first<T>(predicate: BooleanConstructor): OperatorFunctio
export declare function first<T, D>(predicate: BooleanConstructor, defaultValue: D): OperatorFunction<T, TruthyTypesOf<T> | D>;
export declare function first<T, S extends T>(predicate: (value: T, index: number, source: Observable<T>) => value is S, defaultValue?: S): OperatorFunction<T, S>;
export declare function first<T, S extends T, D>(predicate: (value: T, index: number, source: Observable<T>) => value is S, defaultValue: D): OperatorFunction<T, S | D>;
export declare function first<T, D>(predicate: (value: T, index: number, source: Observable<T>) => false, defaultValue: D): OperatorFunction<T, D>;
export declare function first<T>(predicate: (value: T, index: number, source: Observable<T>) => false): OperatorFunction<T, never>;
export declare function first<T, D = T>(predicate: (value: T, index: number, source: Observable<T>) => boolean, defaultValue?: D): OperatorFunction<T, T | D>;

export declare const flatMap: typeof mergeMap;
Expand All @@ -150,8 +148,6 @@ export declare function last<T>(predicate: BooleanConstructor): OperatorFunction
export declare function last<T, D>(predicate: BooleanConstructor, defaultValue: D): OperatorFunction<T, TruthyTypesOf<T> | D>;
export declare function last<T, D = T>(predicate?: null, defaultValue?: D): OperatorFunction<T, T | D>;
export declare function last<T, S extends T>(predicate: (value: T, index: number, source: Observable<T>) => value is S, defaultValue?: S): OperatorFunction<T, S>;
export declare function last<T, D>(predicate: (value: T, index: number, source: Observable<T>) => false, defaultValue: D): OperatorFunction<T, D>;
export declare function last<T>(predicate: (value: T, index: number, source: Observable<T>) => false): OperatorFunction<T, never>;
export declare function last<T, D = T>(predicate: (value: T, index: number, source: Observable<T>) => boolean, defaultValue?: D): OperatorFunction<T, T | D>;

export declare function map<T, R>(project: (value: T, index: number) => R, thisArg?: any): OperatorFunction<T, R>;
Expand Down Expand Up @@ -256,7 +252,6 @@ export declare function shareReplay<T>(config: ShareReplayConfig): MonoTypeOpera
export declare function shareReplay<T>(bufferSize?: number, windowTime?: number, scheduler?: SchedulerLike): MonoTypeOperatorFunction<T>;

export declare function single<T>(predicate: BooleanConstructor): OperatorFunction<T, TruthyTypesOf<T>>;
export declare function single<T>(predicate: (value: T, index: number, source: Observable<T>) => false): OperatorFunction<T, never>;
export declare function single<T>(predicate?: (value: T, index: number, source: Observable<T>) => boolean): MonoTypeOperatorFunction<T>;

export declare function skip<T>(count: number): MonoTypeOperatorFunction<T>;
Expand Down Expand Up @@ -298,8 +293,6 @@ export declare function takeLast<T>(count: number): MonoTypeOperatorFunction<T>;

export declare function takeUntil<T>(notifier: ObservableInput<any>): MonoTypeOperatorFunction<T>;

export declare function takeWhile<T>(predicate: (value: T, index: number) => false, inclusive: true): MonoTypeOperatorFunction<T>;
export declare function takeWhile<T>(predicate: (value: T, index: number) => false, inclusive?: false): OperatorFunction<T, never>;
export declare function takeWhile<T>(predicate: BooleanConstructor): OperatorFunction<T, Exclude<T, Falsy> extends never ? never : T>;
export declare function takeWhile<T>(predicate: BooleanConstructor, inclusive: false): OperatorFunction<T, Exclude<T, Falsy> extends never ? never : T>;
export declare function takeWhile<T>(predicate: BooleanConstructor, inclusive: true): MonoTypeOperatorFunction<T>;
Expand Down
17 changes: 13 additions & 4 deletions spec-dtslint/observables/iif-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,19 @@ it('should error for incorrect parameters', () => {
});

it('should infer correctly', () => {
const r0 = iif(() => false, a$, b$); // $ExpectType Observable<B>
const r1 = iif(() => true, a$, b$); // $ExpectType Observable<A>
const r0 = iif(() => false, a$, b$); // $ExpectType Observable<A | B>
const r1 = iif(() => true, a$, b$); // $ExpectType Observable<A | B>
const r2 = iif(randomBoolean, a$, b$); // $ExpectType Observable<A | B>
const r3 = iif(() => false, a$, EMPTY); // $ExpectType Observable<never>
const r4 = iif(() => true, EMPTY, b$); // $ExpectType Observable<never>
const r3 = iif(() => false, a$, EMPTY); // $ExpectType Observable<A>
const r4 = iif(() => true, EMPTY, b$); // $ExpectType Observable<B>
const r5 = iif(randomBoolean, EMPTY, EMPTY); // $ExpectType Observable<never>
});


it('should support inference from a predicate that returns any', () => {
function alwaysTrueButReturnsAny(): any {
return true;
}

const o$ = iif(alwaysTrueButReturnsAny, a$, b$) // $ExpectType Observable<A | B>
});
10 changes: 9 additions & 1 deletion spec-dtslint/operators/first-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,12 @@ it('should work properly with the Boolean constructor', () => {
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">
})
});

it('should support inference from a predicate that returns any', () => {
function isTruthy(value: number): any {
return !!value;
}

const o$ = of(1).pipe(first(isTruthy)); // $ExpectType Observable<number>
});
14 changes: 11 additions & 3 deletions spec-dtslint/operators/last-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,21 @@ it('should default D to T with a predicate', () => {
});

it('should handle predicates that always return false properly', () => {
const a = of('foo', 'bar').pipe(last(() => false as const)); // $ExpectType Observable<never>
const b = of('foo', 'bar').pipe(last(() => false as const, 1337 as const)); // $ExpectType Observable<1337>
const a = of('foo', 'bar').pipe(last(() => false as const)); // $ExpectType Observable<string>
const b = of('foo', 'bar').pipe(last(() => false as const, 1337 as const)); // $ExpectType Observable<string | 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<never>
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">
})
});

it('should support inference from a predicate that returns any', () => {
function isTruthy(value: number): any {
return !!value;
}

const o$ = of(1).pipe(last(isTruthy)); // $ExpectType Observable<number>
});
10 changes: 9 additions & 1 deletion spec-dtslint/operators/single-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,13 @@ it('should handle Boolean constructor properly', () => {
});

it('should handle predicates that always return false properly', () => {
const a = of(1, 2, 3, 4).pipe(single(() => false as const)); // $ExpectType Observable<never>
const a = of(1, 2, 3, 4).pipe(single(() => false as const)); // $ExpectType Observable<number>
});

it('should support inference from a predicate that returns any', () => {
function isTruthy(value: number): any {
return !!value;
}

const o$ = of(1).pipe(single(isTruthy)); // $ExpectType Observable<number>
});
10 changes: 9 additions & 1 deletion spec-dtslint/operators/takeWhile-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ it('should properly support Boolean constructor', () => {
});

it('should properly handle predicates that always return false', () => {
const a = of(1, 2, 3).pipe(takeWhile(() => false as const)); // $ExpectType Observable<never>
const a = of(1, 2, 3).pipe(takeWhile(() => false as const)); // $ExpectType Observable<number>
const b = of(1, 2, 3).pipe(takeWhile(() => false as const, true)); // $ExpectType Observable<number>
});

it('should support inference from a predicate that returns any', () => {
function isTruthy(value: number): any {
return !!value;
}

const o$ = of(1).pipe(takeWhile(isTruthy)); // $ExpectType Observable<number>
});
6 changes: 0 additions & 6 deletions src/internal/observable/iif.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,6 @@ import { Observable } from '../Observable';
import { defer } from './defer';
import { ObservableInput } from '../types';

export function iif<T>(condition: () => true, trueResult: ObservableInput<T>, falseResult: ObservableInput<any>): Observable<T>;

export function iif<F>(condition: () => false, trueResult: ObservableInput<any>, falseResult: ObservableInput<F>): Observable<F>;

export function iif<T, F>(condition: () => boolean, trueResult: ObservableInput<T>, falseResult: ObservableInput<F>): Observable<T | F>;

/**
* Checks a boolean at subscription time, and chooses between one of two observable sources
*
Expand Down
2 changes: 0 additions & 2 deletions src/internal/operators/first.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ export function first<T, S extends T, D>(
predicate: (value: T, index: number, source: Observable<T>) => value is S,
defaultValue: D
): OperatorFunction<T, S | D>;
export function first<T, D>(predicate: (value: T, index: number, source: Observable<T>) => false, defaultValue: D): OperatorFunction<T, D>;
export function first<T>(predicate: (value: T, index: number, source: Observable<T>) => false): OperatorFunction<T, never>;
export function first<T, D = T>(
predicate: (value: T, index: number, source: Observable<T>) => boolean,
defaultValue?: D
Expand Down
2 changes: 0 additions & 2 deletions src/internal/operators/last.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ export function last<T, S extends T>(
predicate: (value: T, index: number, source: Observable<T>) => value is S,
defaultValue?: S
): OperatorFunction<T, S>;
export function last<T, D>(predicate: (value: T, index: number, source: Observable<T>) => false, defaultValue: D): OperatorFunction<T, D>;
export function last<T>(predicate: (value: T, index: number, source: Observable<T>) => false): OperatorFunction<T, never>;
export function last<T, D = T>(
predicate: (value: T, index: number, source: Observable<T>) => boolean,
defaultValue?: D
Expand Down
1 change: 0 additions & 1 deletion src/internal/operators/single.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { operate } from '../util/lift';
import { OperatorSubscriber } from './OperatorSubscriber';

export function single<T>(predicate: BooleanConstructor): OperatorFunction<T, TruthyTypesOf<T>>;
export function single<T>(predicate: (value: T, index: number, source: Observable<T>) => false): OperatorFunction<T, never>;
export function single<T>(predicate?: (value: T, index: number, source: Observable<T>) => boolean): MonoTypeOperatorFunction<T>;

/**
Expand Down
2 changes: 0 additions & 2 deletions src/internal/operators/takeWhile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import { OperatorFunction, MonoTypeOperatorFunction, Falsy } from '../types';
import { operate } from '../util/lift';
import { OperatorSubscriber } from './OperatorSubscriber';

export function takeWhile<T>(predicate: (value: T, index: number) => false, inclusive: true): MonoTypeOperatorFunction<T>;
export function takeWhile<T>(predicate: (value: T, index: number) => false, inclusive?: false): OperatorFunction<T, never>;
export function takeWhile<T>(predicate: BooleanConstructor): OperatorFunction<T, Exclude<T, Falsy> extends never ? never : T>;
export function takeWhile<T>(
predicate: BooleanConstructor,
Expand Down