Skip to content

Commit b36c8a0

Browse files
authored
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
1 parent 1e7a77c commit b36c8a0

File tree

9 files changed

+264
-124
lines changed

9 files changed

+264
-124
lines changed

src/lib/es5.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,7 @@ interface Boolean {
513513

514514
interface BooleanConstructor {
515515
new(value?: any): Boolean;
516-
<T>(value?: T): value is Exclude<T, false | null | undefined | '' | 0>;
516+
<T>(value?: T): boolean;
517517
readonly prototype: Boolean;
518518
}
519519

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//// [booleanFilterAnyArray.ts]
2+
interface Bullean { }
3+
interface BulleanConstructor {
4+
new(v1?: any): Bullean;
5+
<T>(v2?: T): v2 is T;
6+
}
7+
8+
interface Ari<T> {
9+
filter<S extends T>(cb1: (value: T) => value is S): T extends any ? Ari<any> : Ari<S>;
10+
filter(cb2: (value: T) => unknown): Ari<T>;
11+
}
12+
declare var Bullean: BulleanConstructor;
13+
declare let anys: Ari<any>;
14+
var xs: Ari<any>;
15+
var xs = anys.filter(Bullean)
16+
17+
declare let realanys: any[];
18+
var ys: any[];
19+
var ys = realanys.filter(Boolean)
20+
21+
var foo = [{ name: 'x' }]
22+
var foor: Array<{name: string}>
23+
var foor = foo.filter(x => x.name)
24+
var foos: Array<boolean>
25+
var foos = [true, true, false, null].filter((thing): thing is boolean => thing !== null)
26+
27+
28+
//// [booleanFilterAnyArray.js]
29+
var xs;
30+
var xs = anys.filter(Bullean);
31+
var ys;
32+
var ys = realanys.filter(Boolean);
33+
var foo = [{ name: 'x' }];
34+
var foor;
35+
var foor = foo.filter(function (x) { return x.name; });
36+
var foos;
37+
var foos = [true, true, false, null].filter(function (thing) { return thing !== null; });
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
=== tests/cases/compiler/booleanFilterAnyArray.ts ===
2+
interface Bullean { }
3+
>Bullean : Symbol(Bullean, Decl(booleanFilterAnyArray.ts, 0, 0), Decl(booleanFilterAnyArray.ts, 10, 11))
4+
5+
interface BulleanConstructor {
6+
>BulleanConstructor : Symbol(BulleanConstructor, Decl(booleanFilterAnyArray.ts, 0, 21))
7+
8+
new(v1?: any): Bullean;
9+
>v1 : Symbol(v1, Decl(booleanFilterAnyArray.ts, 2, 8))
10+
>Bullean : Symbol(Bullean, Decl(booleanFilterAnyArray.ts, 0, 0), Decl(booleanFilterAnyArray.ts, 10, 11))
11+
12+
<T>(v2?: T): v2 is T;
13+
>T : Symbol(T, Decl(booleanFilterAnyArray.ts, 3, 5))
14+
>v2 : Symbol(v2, Decl(booleanFilterAnyArray.ts, 3, 8))
15+
>T : Symbol(T, Decl(booleanFilterAnyArray.ts, 3, 5))
16+
>v2 : Symbol(v2, Decl(booleanFilterAnyArray.ts, 3, 8))
17+
>T : Symbol(T, Decl(booleanFilterAnyArray.ts, 3, 5))
18+
}
19+
20+
interface Ari<T> {
21+
>Ari : Symbol(Ari, Decl(booleanFilterAnyArray.ts, 4, 1))
22+
>T : Symbol(T, Decl(booleanFilterAnyArray.ts, 6, 14))
23+
24+
filter<S extends T>(cb1: (value: T) => value is S): T extends any ? Ari<any> : Ari<S>;
25+
>filter : Symbol(Ari.filter, Decl(booleanFilterAnyArray.ts, 6, 18), Decl(booleanFilterAnyArray.ts, 7, 90))
26+
>S : Symbol(S, Decl(booleanFilterAnyArray.ts, 7, 11))
27+
>T : Symbol(T, Decl(booleanFilterAnyArray.ts, 6, 14))
28+
>cb1 : Symbol(cb1, Decl(booleanFilterAnyArray.ts, 7, 24))
29+
>value : Symbol(value, Decl(booleanFilterAnyArray.ts, 7, 30))
30+
>T : Symbol(T, Decl(booleanFilterAnyArray.ts, 6, 14))
31+
>value : Symbol(value, Decl(booleanFilterAnyArray.ts, 7, 30))
32+
>S : Symbol(S, Decl(booleanFilterAnyArray.ts, 7, 11))
33+
>T : Symbol(T, Decl(booleanFilterAnyArray.ts, 6, 14))
34+
>Ari : Symbol(Ari, Decl(booleanFilterAnyArray.ts, 4, 1))
35+
>Ari : Symbol(Ari, Decl(booleanFilterAnyArray.ts, 4, 1))
36+
>S : Symbol(S, Decl(booleanFilterAnyArray.ts, 7, 11))
37+
38+
filter(cb2: (value: T) => unknown): Ari<T>;
39+
>filter : Symbol(Ari.filter, Decl(booleanFilterAnyArray.ts, 6, 18), Decl(booleanFilterAnyArray.ts, 7, 90))
40+
>cb2 : Symbol(cb2, Decl(booleanFilterAnyArray.ts, 8, 11))
41+
>value : Symbol(value, Decl(booleanFilterAnyArray.ts, 8, 17))
42+
>T : Symbol(T, Decl(booleanFilterAnyArray.ts, 6, 14))
43+
>Ari : Symbol(Ari, Decl(booleanFilterAnyArray.ts, 4, 1))
44+
>T : Symbol(T, Decl(booleanFilterAnyArray.ts, 6, 14))
45+
}
46+
declare var Bullean: BulleanConstructor;
47+
>Bullean : Symbol(Bullean, Decl(booleanFilterAnyArray.ts, 0, 0), Decl(booleanFilterAnyArray.ts, 10, 11))
48+
>BulleanConstructor : Symbol(BulleanConstructor, Decl(booleanFilterAnyArray.ts, 0, 21))
49+
50+
declare let anys: Ari<any>;
51+
>anys : Symbol(anys, Decl(booleanFilterAnyArray.ts, 11, 11))
52+
>Ari : Symbol(Ari, Decl(booleanFilterAnyArray.ts, 4, 1))
53+
54+
var xs: Ari<any>;
55+
>xs : Symbol(xs, Decl(booleanFilterAnyArray.ts, 12, 3), Decl(booleanFilterAnyArray.ts, 13, 3))
56+
>Ari : Symbol(Ari, Decl(booleanFilterAnyArray.ts, 4, 1))
57+
58+
var xs = anys.filter(Bullean)
59+
>xs : Symbol(xs, Decl(booleanFilterAnyArray.ts, 12, 3), Decl(booleanFilterAnyArray.ts, 13, 3))
60+
>anys.filter : Symbol(Ari.filter, Decl(booleanFilterAnyArray.ts, 6, 18), Decl(booleanFilterAnyArray.ts, 7, 90))
61+
>anys : Symbol(anys, Decl(booleanFilterAnyArray.ts, 11, 11))
62+
>filter : Symbol(Ari.filter, Decl(booleanFilterAnyArray.ts, 6, 18), Decl(booleanFilterAnyArray.ts, 7, 90))
63+
>Bullean : Symbol(Bullean, Decl(booleanFilterAnyArray.ts, 0, 0), Decl(booleanFilterAnyArray.ts, 10, 11))
64+
65+
declare let realanys: any[];
66+
>realanys : Symbol(realanys, Decl(booleanFilterAnyArray.ts, 15, 11))
67+
68+
var ys: any[];
69+
>ys : Symbol(ys, Decl(booleanFilterAnyArray.ts, 16, 3), Decl(booleanFilterAnyArray.ts, 17, 3))
70+
71+
var ys = realanys.filter(Boolean)
72+
>ys : Symbol(ys, Decl(booleanFilterAnyArray.ts, 16, 3), Decl(booleanFilterAnyArray.ts, 17, 3))
73+
>realanys.filter : Symbol(Array.filter, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
74+
>realanys : Symbol(realanys, Decl(booleanFilterAnyArray.ts, 15, 11))
75+
>filter : Symbol(Array.filter, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
76+
>Boolean : Symbol(Boolean, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
77+
78+
var foo = [{ name: 'x' }]
79+
>foo : Symbol(foo, Decl(booleanFilterAnyArray.ts, 19, 3))
80+
>name : Symbol(name, Decl(booleanFilterAnyArray.ts, 19, 12))
81+
82+
var foor: Array<{name: string}>
83+
>foor : Symbol(foor, Decl(booleanFilterAnyArray.ts, 20, 3), Decl(booleanFilterAnyArray.ts, 21, 3))
84+
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
85+
>name : Symbol(name, Decl(booleanFilterAnyArray.ts, 20, 17))
86+
87+
var foor = foo.filter(x => x.name)
88+
>foor : Symbol(foor, Decl(booleanFilterAnyArray.ts, 20, 3), Decl(booleanFilterAnyArray.ts, 21, 3))
89+
>foo.filter : Symbol(Array.filter, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
90+
>foo : Symbol(foo, Decl(booleanFilterAnyArray.ts, 19, 3))
91+
>filter : Symbol(Array.filter, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
92+
>x : Symbol(x, Decl(booleanFilterAnyArray.ts, 21, 22))
93+
>x.name : Symbol(name, Decl(booleanFilterAnyArray.ts, 19, 12))
94+
>x : Symbol(x, Decl(booleanFilterAnyArray.ts, 21, 22))
95+
>name : Symbol(name, Decl(booleanFilterAnyArray.ts, 19, 12))
96+
97+
var foos: Array<boolean>
98+
>foos : Symbol(foos, Decl(booleanFilterAnyArray.ts, 22, 3), Decl(booleanFilterAnyArray.ts, 23, 3))
99+
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
100+
101+
var foos = [true, true, false, null].filter((thing): thing is boolean => thing !== null)
102+
>foos : Symbol(foos, Decl(booleanFilterAnyArray.ts, 22, 3), Decl(booleanFilterAnyArray.ts, 23, 3))
103+
>[true, true, false, null].filter : Symbol(Array.filter, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
104+
>filter : Symbol(Array.filter, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
105+
>thing : Symbol(thing, Decl(booleanFilterAnyArray.ts, 23, 45))
106+
>thing : Symbol(thing, Decl(booleanFilterAnyArray.ts, 23, 45))
107+
>thing : Symbol(thing, Decl(booleanFilterAnyArray.ts, 23, 45))
108+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
=== tests/cases/compiler/booleanFilterAnyArray.ts ===
2+
interface Bullean { }
3+
interface BulleanConstructor {
4+
new(v1?: any): Bullean;
5+
>v1 : any
6+
7+
<T>(v2?: T): v2 is T;
8+
>v2 : T
9+
}
10+
11+
interface Ari<T> {
12+
filter<S extends T>(cb1: (value: T) => value is S): T extends any ? Ari<any> : Ari<S>;
13+
>filter : { <S extends T>(cb1: (value: T) => value is S): T extends any ? Ari<any> : Ari<S>; (cb2: (value: T) => unknown): Ari<T>; }
14+
>cb1 : (value: T) => value is S
15+
>value : T
16+
17+
filter(cb2: (value: T) => unknown): Ari<T>;
18+
>filter : { <S extends T>(cb1: (value: T) => value is S): T extends any ? Ari<any> : Ari<S>; (cb2: (value: T) => unknown): Ari<T>; }
19+
>cb2 : (value: T) => unknown
20+
>value : T
21+
}
22+
declare var Bullean: BulleanConstructor;
23+
>Bullean : BulleanConstructor
24+
25+
declare let anys: Ari<any>;
26+
>anys : Ari<any>
27+
28+
var xs: Ari<any>;
29+
>xs : Ari<any>
30+
31+
var xs = anys.filter(Bullean)
32+
>xs : Ari<any>
33+
>anys.filter(Bullean) : Ari<any>
34+
>anys.filter : { <S extends any>(cb1: (value: any) => value is S): Ari<any>; (cb2: (value: any) => unknown): Ari<any>; }
35+
>anys : Ari<any>
36+
>filter : { <S extends any>(cb1: (value: any) => value is S): Ari<any>; (cb2: (value: any) => unknown): Ari<any>; }
37+
>Bullean : BulleanConstructor
38+
39+
declare let realanys: any[];
40+
>realanys : any[]
41+
42+
var ys: any[];
43+
>ys : any[]
44+
45+
var ys = realanys.filter(Boolean)
46+
>ys : any[]
47+
>realanys.filter(Boolean) : any[]
48+
>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[]; }
49+
>realanys : any[]
50+
>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[]; }
51+
>Boolean : BooleanConstructor
52+
53+
var foo = [{ name: 'x' }]
54+
>foo : { name: string; }[]
55+
>[{ name: 'x' }] : { name: string; }[]
56+
>{ name: 'x' } : { name: string; }
57+
>name : string
58+
>'x' : "x"
59+
60+
var foor: Array<{name: string}>
61+
>foor : { name: string; }[]
62+
>name : string
63+
64+
var foor = foo.filter(x => x.name)
65+
>foor : { name: string; }[]
66+
>foo.filter(x => x.name) : { name: string; }[]
67+
>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; }[]; }
68+
>foo : { name: string; }[]
69+
>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; }[]; }
70+
>x => x.name : (x: { name: string; }) => string
71+
>x : { name: string; }
72+
>x.name : string
73+
>x : { name: string; }
74+
>name : string
75+
76+
var foos: Array<boolean>
77+
>foos : boolean[]
78+
79+
var foos = [true, true, false, null].filter((thing): thing is boolean => thing !== null)
80+
>foos : boolean[]
81+
>[true, true, false, null].filter((thing): thing is boolean => thing !== null) : boolean[]
82+
>[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[]; }
83+
>[true, true, false, null] : boolean[]
84+
>true : true
85+
>true : true
86+
>false : false
87+
>null : null
88+
>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[]; }
89+
>(thing): thing is boolean => thing !== null : (thing: boolean) => thing is boolean
90+
>thing : boolean
91+
>thing !== null : boolean
92+
>thing : boolean
93+
>null : null
94+

tests/baselines/reference/typeGuardBoolean.js

-30
This file was deleted.

tests/baselines/reference/typeGuardBoolean.symbols

-35
This file was deleted.

tests/baselines/reference/typeGuardBoolean.types

-44
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
interface Bullean { }
2+
interface BulleanConstructor {
3+
new(v1?: any): Bullean;
4+
<T>(v2?: T): v2 is T;
5+
}
6+
7+
interface Ari<T> {
8+
filter<S extends T>(cb1: (value: T) => value is S): T extends any ? Ari<any> : Ari<S>;
9+
filter(cb2: (value: T) => unknown): Ari<T>;
10+
}
11+
declare var Bullean: BulleanConstructor;
12+
declare let anys: Ari<any>;
13+
var xs: Ari<any>;
14+
var xs = anys.filter(Bullean)
15+
16+
declare let realanys: any[];
17+
var ys: any[];
18+
var ys = realanys.filter(Boolean)
19+
20+
var foo = [{ name: 'x' }]
21+
var foor: Array<{name: string}>
22+
var foor = foo.filter(x => x.name)
23+
var foos: Array<boolean>
24+
var foos = [true, true, false, null].filter((thing): thing is boolean => thing !== null)

0 commit comments

Comments
 (0)