Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Make anyArray.filter(Boolean) return any[], not unknown[] (#31515)
* Add this-parameter workaround to Array.filter

Allows anys.filter(Boolean) to once again return any[], not unknown[].

* Add any constraint to Boolean factory function

I want to test how well this works.

* Remove Boolean factory type guard

* Remove typeGuardBoolean test
  • Loading branch information
sandersn committed May 22, 2019
1 parent 1e7a77c commit b36c8a0
Show file tree
Hide file tree
Showing 9 changed files with 264 additions and 124 deletions.
2 changes: 1 addition & 1 deletion src/lib/es5.d.ts
Expand Up @@ -513,7 +513,7 @@ interface Boolean {

interface BooleanConstructor {
new(value?: any): Boolean;
<T>(value?: T): value is Exclude<T, false | null | undefined | '' | 0>;
<T>(value?: T): boolean;
readonly prototype: Boolean;
}

Expand Down
37 changes: 37 additions & 0 deletions tests/baselines/reference/booleanFilterAnyArray.js
@@ -0,0 +1,37 @@
//// [booleanFilterAnyArray.ts]
interface Bullean { }
interface BulleanConstructor {
new(v1?: any): Bullean;
<T>(v2?: T): v2 is T;
}

interface Ari<T> {
filter<S extends T>(cb1: (value: T) => value is S): T extends any ? Ari<any> : Ari<S>;
filter(cb2: (value: T) => unknown): Ari<T>;
}
declare var Bullean: BulleanConstructor;
declare let anys: Ari<any>;
var xs: Ari<any>;
var xs = anys.filter(Bullean)

declare let realanys: any[];
var ys: any[];
var ys = realanys.filter(Boolean)

var foo = [{ name: 'x' }]
var foor: Array<{name: string}>
var foor = foo.filter(x => x.name)
var foos: Array<boolean>
var foos = [true, true, false, null].filter((thing): thing is boolean => thing !== null)


//// [booleanFilterAnyArray.js]
var xs;
var xs = anys.filter(Bullean);
var ys;
var ys = realanys.filter(Boolean);
var foo = [{ name: 'x' }];
var foor;
var foor = foo.filter(function (x) { return x.name; });
var foos;
var foos = [true, true, false, null].filter(function (thing) { return thing !== null; });
108 changes: 108 additions & 0 deletions tests/baselines/reference/booleanFilterAnyArray.symbols
@@ -0,0 +1,108 @@
=== tests/cases/compiler/booleanFilterAnyArray.ts ===
interface Bullean { }
>Bullean : Symbol(Bullean, Decl(booleanFilterAnyArray.ts, 0, 0), Decl(booleanFilterAnyArray.ts, 10, 11))

interface BulleanConstructor {
>BulleanConstructor : Symbol(BulleanConstructor, Decl(booleanFilterAnyArray.ts, 0, 21))

new(v1?: any): Bullean;
>v1 : Symbol(v1, Decl(booleanFilterAnyArray.ts, 2, 8))
>Bullean : Symbol(Bullean, Decl(booleanFilterAnyArray.ts, 0, 0), Decl(booleanFilterAnyArray.ts, 10, 11))

<T>(v2?: T): v2 is T;
>T : Symbol(T, Decl(booleanFilterAnyArray.ts, 3, 5))
>v2 : Symbol(v2, Decl(booleanFilterAnyArray.ts, 3, 8))
>T : Symbol(T, Decl(booleanFilterAnyArray.ts, 3, 5))
>v2 : Symbol(v2, Decl(booleanFilterAnyArray.ts, 3, 8))
>T : Symbol(T, Decl(booleanFilterAnyArray.ts, 3, 5))
}

interface Ari<T> {
>Ari : Symbol(Ari, Decl(booleanFilterAnyArray.ts, 4, 1))
>T : Symbol(T, Decl(booleanFilterAnyArray.ts, 6, 14))

filter<S extends T>(cb1: (value: T) => value is S): T extends any ? Ari<any> : Ari<S>;
>filter : Symbol(Ari.filter, Decl(booleanFilterAnyArray.ts, 6, 18), Decl(booleanFilterAnyArray.ts, 7, 90))
>S : Symbol(S, Decl(booleanFilterAnyArray.ts, 7, 11))
>T : Symbol(T, Decl(booleanFilterAnyArray.ts, 6, 14))
>cb1 : Symbol(cb1, Decl(booleanFilterAnyArray.ts, 7, 24))
>value : Symbol(value, Decl(booleanFilterAnyArray.ts, 7, 30))
>T : Symbol(T, Decl(booleanFilterAnyArray.ts, 6, 14))
>value : Symbol(value, Decl(booleanFilterAnyArray.ts, 7, 30))
>S : Symbol(S, Decl(booleanFilterAnyArray.ts, 7, 11))
>T : Symbol(T, Decl(booleanFilterAnyArray.ts, 6, 14))
>Ari : Symbol(Ari, Decl(booleanFilterAnyArray.ts, 4, 1))
>Ari : Symbol(Ari, Decl(booleanFilterAnyArray.ts, 4, 1))
>S : Symbol(S, Decl(booleanFilterAnyArray.ts, 7, 11))

filter(cb2: (value: T) => unknown): Ari<T>;
>filter : Symbol(Ari.filter, Decl(booleanFilterAnyArray.ts, 6, 18), Decl(booleanFilterAnyArray.ts, 7, 90))
>cb2 : Symbol(cb2, Decl(booleanFilterAnyArray.ts, 8, 11))
>value : Symbol(value, Decl(booleanFilterAnyArray.ts, 8, 17))
>T : Symbol(T, Decl(booleanFilterAnyArray.ts, 6, 14))
>Ari : Symbol(Ari, Decl(booleanFilterAnyArray.ts, 4, 1))
>T : Symbol(T, Decl(booleanFilterAnyArray.ts, 6, 14))
}
declare var Bullean: BulleanConstructor;
>Bullean : Symbol(Bullean, Decl(booleanFilterAnyArray.ts, 0, 0), Decl(booleanFilterAnyArray.ts, 10, 11))
>BulleanConstructor : Symbol(BulleanConstructor, Decl(booleanFilterAnyArray.ts, 0, 21))

declare let anys: Ari<any>;
>anys : Symbol(anys, Decl(booleanFilterAnyArray.ts, 11, 11))
>Ari : Symbol(Ari, Decl(booleanFilterAnyArray.ts, 4, 1))

var xs: Ari<any>;
>xs : Symbol(xs, Decl(booleanFilterAnyArray.ts, 12, 3), Decl(booleanFilterAnyArray.ts, 13, 3))
>Ari : Symbol(Ari, Decl(booleanFilterAnyArray.ts, 4, 1))

var xs = anys.filter(Bullean)
>xs : Symbol(xs, Decl(booleanFilterAnyArray.ts, 12, 3), Decl(booleanFilterAnyArray.ts, 13, 3))
>anys.filter : Symbol(Ari.filter, Decl(booleanFilterAnyArray.ts, 6, 18), Decl(booleanFilterAnyArray.ts, 7, 90))
>anys : Symbol(anys, Decl(booleanFilterAnyArray.ts, 11, 11))
>filter : Symbol(Ari.filter, Decl(booleanFilterAnyArray.ts, 6, 18), Decl(booleanFilterAnyArray.ts, 7, 90))
>Bullean : Symbol(Bullean, Decl(booleanFilterAnyArray.ts, 0, 0), Decl(booleanFilterAnyArray.ts, 10, 11))

declare let realanys: any[];
>realanys : Symbol(realanys, Decl(booleanFilterAnyArray.ts, 15, 11))

var ys: any[];
>ys : Symbol(ys, Decl(booleanFilterAnyArray.ts, 16, 3), Decl(booleanFilterAnyArray.ts, 17, 3))

var ys = realanys.filter(Boolean)
>ys : Symbol(ys, Decl(booleanFilterAnyArray.ts, 16, 3), Decl(booleanFilterAnyArray.ts, 17, 3))
>realanys.filter : Symbol(Array.filter, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>realanys : Symbol(realanys, Decl(booleanFilterAnyArray.ts, 15, 11))
>filter : Symbol(Array.filter, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>Boolean : Symbol(Boolean, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))

var foo = [{ name: 'x' }]
>foo : Symbol(foo, Decl(booleanFilterAnyArray.ts, 19, 3))
>name : Symbol(name, Decl(booleanFilterAnyArray.ts, 19, 12))

var foor: Array<{name: string}>
>foor : Symbol(foor, Decl(booleanFilterAnyArray.ts, 20, 3), Decl(booleanFilterAnyArray.ts, 21, 3))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>name : Symbol(name, Decl(booleanFilterAnyArray.ts, 20, 17))

var foor = foo.filter(x => x.name)
>foor : Symbol(foor, Decl(booleanFilterAnyArray.ts, 20, 3), Decl(booleanFilterAnyArray.ts, 21, 3))
>foo.filter : Symbol(Array.filter, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>foo : Symbol(foo, Decl(booleanFilterAnyArray.ts, 19, 3))
>filter : Symbol(Array.filter, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>x : Symbol(x, Decl(booleanFilterAnyArray.ts, 21, 22))
>x.name : Symbol(name, Decl(booleanFilterAnyArray.ts, 19, 12))
>x : Symbol(x, Decl(booleanFilterAnyArray.ts, 21, 22))
>name : Symbol(name, Decl(booleanFilterAnyArray.ts, 19, 12))

var foos: Array<boolean>
>foos : Symbol(foos, Decl(booleanFilterAnyArray.ts, 22, 3), Decl(booleanFilterAnyArray.ts, 23, 3))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))

var foos = [true, true, false, null].filter((thing): thing is boolean => thing !== null)
>foos : Symbol(foos, Decl(booleanFilterAnyArray.ts, 22, 3), Decl(booleanFilterAnyArray.ts, 23, 3))
>[true, true, false, null].filter : Symbol(Array.filter, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>filter : Symbol(Array.filter, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>thing : Symbol(thing, Decl(booleanFilterAnyArray.ts, 23, 45))
>thing : Symbol(thing, Decl(booleanFilterAnyArray.ts, 23, 45))
>thing : Symbol(thing, Decl(booleanFilterAnyArray.ts, 23, 45))

94 changes: 94 additions & 0 deletions tests/baselines/reference/booleanFilterAnyArray.types
@@ -0,0 +1,94 @@
=== tests/cases/compiler/booleanFilterAnyArray.ts ===
interface Bullean { }
interface BulleanConstructor {
new(v1?: any): Bullean;
>v1 : any

<T>(v2?: T): v2 is T;
>v2 : T
}

interface Ari<T> {
filter<S extends T>(cb1: (value: T) => value is S): T extends any ? Ari<any> : Ari<S>;
>filter : { <S extends T>(cb1: (value: T) => value is S): T extends any ? Ari<any> : Ari<S>; (cb2: (value: T) => unknown): Ari<T>; }
>cb1 : (value: T) => value is S
>value : T

filter(cb2: (value: T) => unknown): Ari<T>;
>filter : { <S extends T>(cb1: (value: T) => value is S): T extends any ? Ari<any> : Ari<S>; (cb2: (value: T) => unknown): Ari<T>; }
>cb2 : (value: T) => unknown
>value : T
}
declare var Bullean: BulleanConstructor;
>Bullean : BulleanConstructor

declare let anys: Ari<any>;
>anys : Ari<any>

var xs: Ari<any>;
>xs : Ari<any>

var xs = anys.filter(Bullean)
>xs : Ari<any>
>anys.filter(Bullean) : Ari<any>
>anys.filter : { <S extends any>(cb1: (value: any) => value is S): Ari<any>; (cb2: (value: any) => unknown): Ari<any>; }
>anys : Ari<any>
>filter : { <S extends any>(cb1: (value: any) => value is S): Ari<any>; (cb2: (value: any) => unknown): Ari<any>; }
>Bullean : BulleanConstructor

declare let realanys: any[];
>realanys : any[]

var ys: any[];
>ys : any[]

var ys = realanys.filter(Boolean)
>ys : any[]
>realanys.filter(Boolean) : any[]
>realanys.filter : { <S extends any>(callbackfn: (value: any, index: number, array: any[]) => value is S, thisArg?: any): S[]; (callbackfn: (value: any, index: number, array: any[]) => unknown, thisArg?: any): any[]; }
>realanys : any[]
>filter : { <S extends any>(callbackfn: (value: any, index: number, array: any[]) => value is S, thisArg?: any): S[]; (callbackfn: (value: any, index: number, array: any[]) => unknown, thisArg?: any): any[]; }
>Boolean : BooleanConstructor

var foo = [{ name: 'x' }]
>foo : { name: string; }[]
>[{ name: 'x' }] : { name: string; }[]
>{ name: 'x' } : { name: string; }
>name : string
>'x' : "x"

var foor: Array<{name: string}>
>foor : { name: string; }[]
>name : string

var foor = foo.filter(x => x.name)
>foor : { name: string; }[]
>foo.filter(x => x.name) : { name: string; }[]
>foo.filter : { <S extends { name: string; }>(callbackfn: (value: { name: string; }, index: number, array: { name: string; }[]) => value is S, thisArg?: any): S[]; (callbackfn: (value: { name: string; }, index: number, array: { name: string; }[]) => unknown, thisArg?: any): { name: string; }[]; }
>foo : { name: string; }[]
>filter : { <S extends { name: string; }>(callbackfn: (value: { name: string; }, index: number, array: { name: string; }[]) => value is S, thisArg?: any): S[]; (callbackfn: (value: { name: string; }, index: number, array: { name: string; }[]) => unknown, thisArg?: any): { name: string; }[]; }
>x => x.name : (x: { name: string; }) => string
>x : { name: string; }
>x.name : string
>x : { name: string; }
>name : string

var foos: Array<boolean>
>foos : boolean[]

var foos = [true, true, false, null].filter((thing): thing is boolean => thing !== null)
>foos : boolean[]
>[true, true, false, null].filter((thing): thing is boolean => thing !== null) : boolean[]
>[true, true, false, null].filter : { <S extends boolean>(callbackfn: (value: boolean, index: number, array: boolean[]) => value is S, thisArg?: any): S[]; (callbackfn: (value: boolean, index: number, array: boolean[]) => unknown, thisArg?: any): boolean[]; }
>[true, true, false, null] : boolean[]
>true : true
>true : true
>false : false
>null : null
>filter : { <S extends boolean>(callbackfn: (value: boolean, index: number, array: boolean[]) => value is S, thisArg?: any): S[]; (callbackfn: (value: boolean, index: number, array: boolean[]) => unknown, thisArg?: any): boolean[]; }
>(thing): thing is boolean => thing !== null : (thing: boolean) => thing is boolean
>thing : boolean
>thing !== null : boolean
>thing : boolean
>null : null

30 changes: 0 additions & 30 deletions tests/baselines/reference/typeGuardBoolean.js

This file was deleted.

35 changes: 0 additions & 35 deletions tests/baselines/reference/typeGuardBoolean.symbols

This file was deleted.

44 changes: 0 additions & 44 deletions tests/baselines/reference/typeGuardBoolean.types

This file was deleted.

24 changes: 24 additions & 0 deletions tests/cases/compiler/booleanFilterAnyArray.ts
@@ -0,0 +1,24 @@
interface Bullean { }
interface BulleanConstructor {
new(v1?: any): Bullean;
<T>(v2?: T): v2 is T;
}

interface Ari<T> {
filter<S extends T>(cb1: (value: T) => value is S): T extends any ? Ari<any> : Ari<S>;
filter(cb2: (value: T) => unknown): Ari<T>;
}
declare var Bullean: BulleanConstructor;
declare let anys: Ari<any>;
var xs: Ari<any>;
var xs = anys.filter(Bullean)

declare let realanys: any[];
var ys: any[];
var ys = realanys.filter(Boolean)

var foo = [{ name: 'x' }]
var foor: Array<{name: string}>
var foor = foo.filter(x => x.name)
var foos: Array<boolean>
var foos = [true, true, false, null].filter((thing): thing is boolean => thing !== null)

0 comments on commit b36c8a0

Please sign in to comment.