Add fallback logic for generating signatures for unions of array members (#53489)

This commit is contained in:
Wesley Wigham 2023-05-16 15:12:37 -07:00 committed by GitHub
parent 58f030072e
commit b0c80207ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 873 additions and 2164 deletions

View File

@ -14262,7 +14262,36 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
* maps primitive types and type parameters are to their apparent types.
*/
function getSignaturesOfType(type: Type, kind: SignatureKind): readonly Signature[] {
return getSignaturesOfStructuredType(getReducedApparentType(type), kind);
const result = getSignaturesOfStructuredType(getReducedApparentType(type), kind);
if (kind === SignatureKind.Call && !length(result) && type.flags & TypeFlags.Union) {
if ((type as UnionType).arrayFallbackSignatures) {
return (type as UnionType).arrayFallbackSignatures!;
}
// If the union is all different instantiations of a member of the global array type...
let memberName: __String;
if (everyType(type, t => !!t.symbol?.parent && isArrayOrTupleSymbol(t.symbol.parent) && (!memberName ? (memberName = t.symbol.escapedName, true) : memberName === t.symbol.escapedName))) {
// Transform the type from `(A[] | B[])["member"]` to `(A | B)[]["member"]` (since we pretend array is covariant anyway)
const arrayArg = mapType(type, t => getMappedType((isReadonlyArraySymbol(t.symbol.parent) ? globalReadonlyArrayType : globalArrayType).typeParameters![0], (t as AnonymousType).mapper!));
const arrayType = createArrayType(arrayArg, someType(type, t => isReadonlyArraySymbol(t.symbol.parent)));
return (type as UnionType).arrayFallbackSignatures = getSignaturesOfType(getTypeOfPropertyOfType(arrayType, memberName!)!, kind);
}
(type as UnionType).arrayFallbackSignatures = result;
}
return result;
}
function isArrayOrTupleSymbol(symbol: Symbol | undefined) {
if (!symbol || !globalArrayType.symbol || !globalReadonlyArrayType.symbol) {
return false;
}
return !!getSymbolIfSameReference(symbol, globalArrayType.symbol) || !!getSymbolIfSameReference(symbol, globalReadonlyArrayType.symbol);
}
function isReadonlyArraySymbol(symbol: Symbol | undefined) {
if (!symbol || !globalReadonlyArrayType.symbol) {
return false;
}
return !!getSymbolIfSameReference(symbol, globalReadonlyArrayType.symbol);
}
function findIndexInfo(indexInfos: readonly IndexInfo[], keyType: Type) {

View File

@ -6465,6 +6465,8 @@ export interface UnionType extends UnionOrIntersectionType {
keyPropertyName?: __String; // Property with unique unit type that exists in every object/intersection in union type
/** @internal */
constituentMap?: Map<TypeId, Type>; // Constituents keyed by unit type discriminants
/** @internal */
arrayFallbackSignatures?: readonly Signature[]; // Special remapped signature list for unions of arrays
}
export interface IntersectionType extends UnionOrIntersectionType {

View File

@ -0,0 +1,36 @@
//// [unionOfArraysFilterCall.ts]
interface Fizz {
id: number;
fizz: string;
}
interface Buzz {
id: number;
buzz: string;
}
([] as Fizz[] | Buzz[]).filter(item => item.id < 5);
([] as Fizz[] | readonly Buzz[]).filter(item => item.id < 5);
([] as Fizz[] | Buzz[]).find(item => item);
declare function isFizz(x: unknown): x is Fizz;
([] as Fizz[] | Buzz[]).find(isFizz);
declare function isBuzz(x: unknown): x is Buzz;
([] as Fizz[] | Buzz[]).find(isBuzz);
([] as Fizz[] | Buzz[]).every(item => item.id < 5);
([] as Fizz[] | Buzz[]).reduce(item => item);
([] as [Fizz] | readonly [Buzz?]).filter(item => item?.id < 5);
//// [unionOfArraysFilterCall.js]
[].filter(item => item.id < 5);
[].filter(item => item.id < 5);
[].find(item => item);
[].find(isFizz);
[].find(isBuzz);
[].every(item => item.id < 5);
[].reduce(item => item);
[].filter(item => (item === null || item === void 0 ? void 0 : item.id) < 5);

View File

@ -0,0 +1,104 @@
=== tests/cases/compiler/unionOfArraysFilterCall.ts ===
interface Fizz {
>Fizz : Symbol(Fizz, Decl(unionOfArraysFilterCall.ts, 0, 0))
id: number;
>id : Symbol(Fizz.id, Decl(unionOfArraysFilterCall.ts, 0, 16))
fizz: string;
>fizz : Symbol(Fizz.fizz, Decl(unionOfArraysFilterCall.ts, 1, 15))
}
interface Buzz {
>Buzz : Symbol(Buzz, Decl(unionOfArraysFilterCall.ts, 3, 1))
id: number;
>id : Symbol(Buzz.id, Decl(unionOfArraysFilterCall.ts, 5, 16))
buzz: string;
>buzz : Symbol(Buzz.buzz, Decl(unionOfArraysFilterCall.ts, 6, 15))
}
([] as Fizz[] | Buzz[]).filter(item => item.id < 5);
>([] as Fizz[] | Buzz[]).filter : Symbol(Array.filter, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>Fizz : Symbol(Fizz, Decl(unionOfArraysFilterCall.ts, 0, 0))
>Buzz : Symbol(Buzz, Decl(unionOfArraysFilterCall.ts, 3, 1))
>filter : Symbol(Array.filter, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>item : Symbol(item, Decl(unionOfArraysFilterCall.ts, 10, 31))
>item.id : Symbol(id, Decl(unionOfArraysFilterCall.ts, 0, 16), Decl(unionOfArraysFilterCall.ts, 5, 16))
>item : Symbol(item, Decl(unionOfArraysFilterCall.ts, 10, 31))
>id : Symbol(id, Decl(unionOfArraysFilterCall.ts, 0, 16), Decl(unionOfArraysFilterCall.ts, 5, 16))
([] as Fizz[] | readonly Buzz[]).filter(item => item.id < 5);
>([] as Fizz[] | readonly Buzz[]).filter : Symbol(filter, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>Fizz : Symbol(Fizz, Decl(unionOfArraysFilterCall.ts, 0, 0))
>Buzz : Symbol(Buzz, Decl(unionOfArraysFilterCall.ts, 3, 1))
>filter : Symbol(filter, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>item : Symbol(item, Decl(unionOfArraysFilterCall.ts, 11, 40))
>item.id : Symbol(id, Decl(unionOfArraysFilterCall.ts, 0, 16), Decl(unionOfArraysFilterCall.ts, 5, 16))
>item : Symbol(item, Decl(unionOfArraysFilterCall.ts, 11, 40))
>id : Symbol(id, Decl(unionOfArraysFilterCall.ts, 0, 16), Decl(unionOfArraysFilterCall.ts, 5, 16))
([] as Fizz[] | Buzz[]).find(item => item);
>([] as Fizz[] | Buzz[]).find : Symbol(Array.find, Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --))
>Fizz : Symbol(Fizz, Decl(unionOfArraysFilterCall.ts, 0, 0))
>Buzz : Symbol(Buzz, Decl(unionOfArraysFilterCall.ts, 3, 1))
>find : Symbol(Array.find, Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --))
>item : Symbol(item, Decl(unionOfArraysFilterCall.ts, 13, 29))
>item : Symbol(item, Decl(unionOfArraysFilterCall.ts, 13, 29))
declare function isFizz(x: unknown): x is Fizz;
>isFizz : Symbol(isFizz, Decl(unionOfArraysFilterCall.ts, 13, 43))
>x : Symbol(x, Decl(unionOfArraysFilterCall.ts, 14, 24))
>x : Symbol(x, Decl(unionOfArraysFilterCall.ts, 14, 24))
>Fizz : Symbol(Fizz, Decl(unionOfArraysFilterCall.ts, 0, 0))
([] as Fizz[] | Buzz[]).find(isFizz);
>([] as Fizz[] | Buzz[]).find : Symbol(Array.find, Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --))
>Fizz : Symbol(Fizz, Decl(unionOfArraysFilterCall.ts, 0, 0))
>Buzz : Symbol(Buzz, Decl(unionOfArraysFilterCall.ts, 3, 1))
>find : Symbol(Array.find, Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --))
>isFizz : Symbol(isFizz, Decl(unionOfArraysFilterCall.ts, 13, 43))
declare function isBuzz(x: unknown): x is Buzz;
>isBuzz : Symbol(isBuzz, Decl(unionOfArraysFilterCall.ts, 15, 37))
>x : Symbol(x, Decl(unionOfArraysFilterCall.ts, 16, 24))
>x : Symbol(x, Decl(unionOfArraysFilterCall.ts, 16, 24))
>Buzz : Symbol(Buzz, Decl(unionOfArraysFilterCall.ts, 3, 1))
([] as Fizz[] | Buzz[]).find(isBuzz);
>([] as Fizz[] | Buzz[]).find : Symbol(Array.find, Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --))
>Fizz : Symbol(Fizz, Decl(unionOfArraysFilterCall.ts, 0, 0))
>Buzz : Symbol(Buzz, Decl(unionOfArraysFilterCall.ts, 3, 1))
>find : Symbol(Array.find, Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --))
>isBuzz : Symbol(isBuzz, Decl(unionOfArraysFilterCall.ts, 15, 37))
([] as Fizz[] | Buzz[]).every(item => item.id < 5);
>([] as Fizz[] | Buzz[]).every : Symbol(Array.every, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>Fizz : Symbol(Fizz, Decl(unionOfArraysFilterCall.ts, 0, 0))
>Buzz : Symbol(Buzz, Decl(unionOfArraysFilterCall.ts, 3, 1))
>every : Symbol(Array.every, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>item : Symbol(item, Decl(unionOfArraysFilterCall.ts, 19, 30))
>item.id : Symbol(id, Decl(unionOfArraysFilterCall.ts, 0, 16), Decl(unionOfArraysFilterCall.ts, 5, 16))
>item : Symbol(item, Decl(unionOfArraysFilterCall.ts, 19, 30))
>id : Symbol(id, Decl(unionOfArraysFilterCall.ts, 0, 16), Decl(unionOfArraysFilterCall.ts, 5, 16))
([] as Fizz[] | Buzz[]).reduce(item => item);
>([] as Fizz[] | Buzz[]).reduce : Symbol(Array.reduce, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --) ... and 1 more)
>Fizz : Symbol(Fizz, Decl(unionOfArraysFilterCall.ts, 0, 0))
>Buzz : Symbol(Buzz, Decl(unionOfArraysFilterCall.ts, 3, 1))
>reduce : Symbol(Array.reduce, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --) ... and 1 more)
>item : Symbol(item, Decl(unionOfArraysFilterCall.ts, 21, 31))
>item : Symbol(item, Decl(unionOfArraysFilterCall.ts, 21, 31))
([] as [Fizz] | readonly [Buzz?]).filter(item => item?.id < 5);
>([] as [Fizz] | readonly [Buzz?]).filter : Symbol(filter, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>Fizz : Symbol(Fizz, Decl(unionOfArraysFilterCall.ts, 0, 0))
>Buzz : Symbol(Buzz, Decl(unionOfArraysFilterCall.ts, 3, 1))
>filter : Symbol(filter, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>item : Symbol(item, Decl(unionOfArraysFilterCall.ts, 24, 41))
>item?.id : Symbol(id, Decl(unionOfArraysFilterCall.ts, 0, 16), Decl(unionOfArraysFilterCall.ts, 5, 16))
>item : Symbol(item, Decl(unionOfArraysFilterCall.ts, 24, 41))
>id : Symbol(id, Decl(unionOfArraysFilterCall.ts, 0, 16), Decl(unionOfArraysFilterCall.ts, 5, 16))

View File

@ -0,0 +1,126 @@
=== tests/cases/compiler/unionOfArraysFilterCall.ts ===
interface Fizz {
id: number;
>id : number
fizz: string;
>fizz : string
}
interface Buzz {
id: number;
>id : number
buzz: string;
>buzz : string
}
([] as Fizz[] | Buzz[]).filter(item => item.id < 5);
>([] as Fizz[] | Buzz[]).filter(item => item.id < 5) : (Fizz | Buzz)[]
>([] as Fizz[] | Buzz[]).filter : { <S extends Fizz>(predicate: (value: Fizz, index: number, array: Fizz[]) => value is S, thisArg?: any): S[]; (predicate: (value: Fizz, index: number, array: Fizz[]) => unknown, thisArg?: any): Fizz[]; } | { <S extends Buzz>(predicate: (value: Buzz, index: number, array: Buzz[]) => value is S, thisArg?: any): S[]; (predicate: (value: Buzz, index: number, array: Buzz[]) => unknown, thisArg?: any): Buzz[]; }
>([] as Fizz[] | Buzz[]) : Fizz[] | Buzz[]
>[] as Fizz[] | Buzz[] : Fizz[] | Buzz[]
>[] : undefined[]
>filter : { <S extends Fizz>(predicate: (value: Fizz, index: number, array: Fizz[]) => value is S, thisArg?: any): S[]; (predicate: (value: Fizz, index: number, array: Fizz[]) => unknown, thisArg?: any): Fizz[]; } | { <S extends Buzz>(predicate: (value: Buzz, index: number, array: Buzz[]) => value is S, thisArg?: any): S[]; (predicate: (value: Buzz, index: number, array: Buzz[]) => unknown, thisArg?: any): Buzz[]; }
>item => item.id < 5 : (item: Fizz | Buzz) => boolean
>item : Fizz | Buzz
>item.id < 5 : boolean
>item.id : number
>item : Fizz | Buzz
>id : number
>5 : 5
([] as Fizz[] | readonly Buzz[]).filter(item => item.id < 5);
>([] as Fizz[] | readonly Buzz[]).filter(item => item.id < 5) : (Fizz | Buzz)[]
>([] as Fizz[] | readonly Buzz[]).filter : { <S extends Fizz>(predicate: (value: Fizz, index: number, array: Fizz[]) => value is S, thisArg?: any): S[]; (predicate: (value: Fizz, index: number, array: Fizz[]) => unknown, thisArg?: any): Fizz[]; } | { <S extends Buzz>(predicate: (value: Buzz, index: number, array: readonly Buzz[]) => value is S, thisArg?: any): S[]; (predicate: (value: Buzz, index: number, array: readonly Buzz[]) => unknown, thisArg?: any): Buzz[]; }
>([] as Fizz[] | readonly Buzz[]) : Fizz[] | readonly Buzz[]
>[] as Fizz[] | readonly Buzz[] : Fizz[] | readonly Buzz[]
>[] : undefined[]
>filter : { <S extends Fizz>(predicate: (value: Fizz, index: number, array: Fizz[]) => value is S, thisArg?: any): S[]; (predicate: (value: Fizz, index: number, array: Fizz[]) => unknown, thisArg?: any): Fizz[]; } | { <S extends Buzz>(predicate: (value: Buzz, index: number, array: readonly Buzz[]) => value is S, thisArg?: any): S[]; (predicate: (value: Buzz, index: number, array: readonly Buzz[]) => unknown, thisArg?: any): Buzz[]; }
>item => item.id < 5 : (item: Fizz | Buzz) => boolean
>item : Fizz | Buzz
>item.id < 5 : boolean
>item.id : number
>item : Fizz | Buzz
>id : number
>5 : 5
([] as Fizz[] | Buzz[]).find(item => item);
>([] as Fizz[] | Buzz[]).find(item => item) : Fizz | Buzz
>([] as Fizz[] | Buzz[]).find : { <S extends Fizz>(predicate: (value: Fizz, index: number, obj: Fizz[]) => value is S, thisArg?: any): S; (predicate: (value: Fizz, index: number, obj: Fizz[]) => unknown, thisArg?: any): Fizz; } | { <S extends Buzz>(predicate: (value: Buzz, index: number, obj: Buzz[]) => value is S, thisArg?: any): S; (predicate: (value: Buzz, index: number, obj: Buzz[]) => unknown, thisArg?: any): Buzz; }
>([] as Fizz[] | Buzz[]) : Fizz[] | Buzz[]
>[] as Fizz[] | Buzz[] : Fizz[] | Buzz[]
>[] : undefined[]
>find : { <S extends Fizz>(predicate: (value: Fizz, index: number, obj: Fizz[]) => value is S, thisArg?: any): S; (predicate: (value: Fizz, index: number, obj: Fizz[]) => unknown, thisArg?: any): Fizz; } | { <S extends Buzz>(predicate: (value: Buzz, index: number, obj: Buzz[]) => value is S, thisArg?: any): S; (predicate: (value: Buzz, index: number, obj: Buzz[]) => unknown, thisArg?: any): Buzz; }
>item => item : (item: Fizz | Buzz) => Fizz | Buzz
>item : Fizz | Buzz
>item : Fizz | Buzz
declare function isFizz(x: unknown): x is Fizz;
>isFizz : (x: unknown) => x is Fizz
>x : unknown
([] as Fizz[] | Buzz[]).find(isFizz);
>([] as Fizz[] | Buzz[]).find(isFizz) : Fizz
>([] as Fizz[] | Buzz[]).find : { <S extends Fizz>(predicate: (value: Fizz, index: number, obj: Fizz[]) => value is S, thisArg?: any): S; (predicate: (value: Fizz, index: number, obj: Fizz[]) => unknown, thisArg?: any): Fizz; } | { <S extends Buzz>(predicate: (value: Buzz, index: number, obj: Buzz[]) => value is S, thisArg?: any): S; (predicate: (value: Buzz, index: number, obj: Buzz[]) => unknown, thisArg?: any): Buzz; }
>([] as Fizz[] | Buzz[]) : Fizz[] | Buzz[]
>[] as Fizz[] | Buzz[] : Fizz[] | Buzz[]
>[] : undefined[]
>find : { <S extends Fizz>(predicate: (value: Fizz, index: number, obj: Fizz[]) => value is S, thisArg?: any): S; (predicate: (value: Fizz, index: number, obj: Fizz[]) => unknown, thisArg?: any): Fizz; } | { <S extends Buzz>(predicate: (value: Buzz, index: number, obj: Buzz[]) => value is S, thisArg?: any): S; (predicate: (value: Buzz, index: number, obj: Buzz[]) => unknown, thisArg?: any): Buzz; }
>isFizz : (x: unknown) => x is Fizz
declare function isBuzz(x: unknown): x is Buzz;
>isBuzz : (x: unknown) => x is Buzz
>x : unknown
([] as Fizz[] | Buzz[]).find(isBuzz);
>([] as Fizz[] | Buzz[]).find(isBuzz) : Buzz
>([] as Fizz[] | Buzz[]).find : { <S extends Fizz>(predicate: (value: Fizz, index: number, obj: Fizz[]) => value is S, thisArg?: any): S; (predicate: (value: Fizz, index: number, obj: Fizz[]) => unknown, thisArg?: any): Fizz; } | { <S extends Buzz>(predicate: (value: Buzz, index: number, obj: Buzz[]) => value is S, thisArg?: any): S; (predicate: (value: Buzz, index: number, obj: Buzz[]) => unknown, thisArg?: any): Buzz; }
>([] as Fizz[] | Buzz[]) : Fizz[] | Buzz[]
>[] as Fizz[] | Buzz[] : Fizz[] | Buzz[]
>[] : undefined[]
>find : { <S extends Fizz>(predicate: (value: Fizz, index: number, obj: Fizz[]) => value is S, thisArg?: any): S; (predicate: (value: Fizz, index: number, obj: Fizz[]) => unknown, thisArg?: any): Fizz; } | { <S extends Buzz>(predicate: (value: Buzz, index: number, obj: Buzz[]) => value is S, thisArg?: any): S; (predicate: (value: Buzz, index: number, obj: Buzz[]) => unknown, thisArg?: any): Buzz; }
>isBuzz : (x: unknown) => x is Buzz
([] as Fizz[] | Buzz[]).every(item => item.id < 5);
>([] as Fizz[] | Buzz[]).every(item => item.id < 5) : boolean
>([] as Fizz[] | Buzz[]).every : { <S extends Fizz>(predicate: (value: Fizz, index: number, array: Fizz[]) => value is S, thisArg?: any): this is S[]; (predicate: (value: Fizz, index: number, array: Fizz[]) => unknown, thisArg?: any): boolean; } | { <S extends Buzz>(predicate: (value: Buzz, index: number, array: Buzz[]) => value is S, thisArg?: any): this is S[]; (predicate: (value: Buzz, index: number, array: Buzz[]) => unknown, thisArg?: any): boolean; }
>([] as Fizz[] | Buzz[]) : Fizz[] | Buzz[]
>[] as Fizz[] | Buzz[] : Fizz[] | Buzz[]
>[] : undefined[]
>every : { <S extends Fizz>(predicate: (value: Fizz, index: number, array: Fizz[]) => value is S, thisArg?: any): this is S[]; (predicate: (value: Fizz, index: number, array: Fizz[]) => unknown, thisArg?: any): boolean; } | { <S extends Buzz>(predicate: (value: Buzz, index: number, array: Buzz[]) => value is S, thisArg?: any): this is S[]; (predicate: (value: Buzz, index: number, array: Buzz[]) => unknown, thisArg?: any): boolean; }
>item => item.id < 5 : (item: Fizz | Buzz) => boolean
>item : Fizz | Buzz
>item.id < 5 : boolean
>item.id : number
>item : Fizz | Buzz
>id : number
>5 : 5
([] as Fizz[] | Buzz[]).reduce(item => item);
>([] as Fizz[] | Buzz[]).reduce(item => item) : Fizz | Buzz
>([] as Fizz[] | Buzz[]).reduce : { (callbackfn: (previousValue: Fizz, currentValue: Fizz, currentIndex: number, array: Fizz[]) => Fizz): Fizz; (callbackfn: (previousValue: Fizz, currentValue: Fizz, currentIndex: number, array: Fizz[]) => Fizz, initialValue: Fizz): Fizz; <U>(callbackfn: (previousValue: U, currentValue: Fizz, currentIndex: number, array: Fizz[]) => U, initialValue: U): U; } | { (callbackfn: (previousValue: Buzz, currentValue: Buzz, currentIndex: number, array: Buzz[]) => Buzz): Buzz; (callbackfn: (previousValue: Buzz, currentValue: Buzz, currentIndex: number, array: Buzz[]) => Buzz, initialValue: Buzz): Buzz; <U>(callbackfn: (previousValue: U, currentValue: Buzz, currentIndex: number, array: Buzz[]) => U, initialValue: U): U; }
>([] as Fizz[] | Buzz[]) : Fizz[] | Buzz[]
>[] as Fizz[] | Buzz[] : Fizz[] | Buzz[]
>[] : undefined[]
>reduce : { (callbackfn: (previousValue: Fizz, currentValue: Fizz, currentIndex: number, array: Fizz[]) => Fizz): Fizz; (callbackfn: (previousValue: Fizz, currentValue: Fizz, currentIndex: number, array: Fizz[]) => Fizz, initialValue: Fizz): Fizz; <U>(callbackfn: (previousValue: U, currentValue: Fizz, currentIndex: number, array: Fizz[]) => U, initialValue: U): U; } | { (callbackfn: (previousValue: Buzz, currentValue: Buzz, currentIndex: number, array: Buzz[]) => Buzz): Buzz; (callbackfn: (previousValue: Buzz, currentValue: Buzz, currentIndex: number, array: Buzz[]) => Buzz, initialValue: Buzz): Buzz; <U>(callbackfn: (previousValue: U, currentValue: Buzz, currentIndex: number, array: Buzz[]) => U, initialValue: U): U; }
>item => item : (item: Fizz | Buzz) => Fizz | Buzz
>item : Fizz | Buzz
>item : Fizz | Buzz
([] as [Fizz] | readonly [Buzz?]).filter(item => item?.id < 5);
>([] as [Fizz] | readonly [Buzz?]).filter(item => item?.id < 5) : (Fizz | Buzz)[]
>([] as [Fizz] | readonly [Buzz?]).filter : { <S extends Fizz>(predicate: (value: Fizz, index: number, array: Fizz[]) => value is S, thisArg?: any): S[]; (predicate: (value: Fizz, index: number, array: Fizz[]) => unknown, thisArg?: any): Fizz[]; } | { <S extends Buzz>(predicate: (value: Buzz, index: number, array: readonly Buzz[]) => value is S, thisArg?: any): S[]; (predicate: (value: Buzz, index: number, array: readonly Buzz[]) => unknown, thisArg?: any): Buzz[]; }
>([] as [Fizz] | readonly [Buzz?]) : [Fizz] | readonly [Buzz?]
>[] as [Fizz] | readonly [Buzz?] : [Fizz] | readonly [Buzz?]
>[] : []
>filter : { <S extends Fizz>(predicate: (value: Fizz, index: number, array: Fizz[]) => value is S, thisArg?: any): S[]; (predicate: (value: Fizz, index: number, array: Fizz[]) => unknown, thisArg?: any): Fizz[]; } | { <S extends Buzz>(predicate: (value: Buzz, index: number, array: readonly Buzz[]) => value is S, thisArg?: any): S[]; (predicate: (value: Buzz, index: number, array: readonly Buzz[]) => unknown, thisArg?: any): Buzz[]; }
>item => item?.id < 5 : (item: Fizz | Buzz) => boolean
>item : Fizz | Buzz
>item?.id < 5 : boolean
>item?.id : number
>item : Fizz | Buzz
>id : number
>5 : 5

View File

@ -1,85 +0,0 @@
tests/cases/compiler/unionOfClassCalls.ts(28,5): error TS2349: This expression is not callable.
Each member of the union type '{ (callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: number[]) => number): number; (callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: number[]) => number, initialValue: number): number; <U>(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: number[]) => U, initialValue: U): U; } | { (callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string): string; (callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string, initialValue: string): string; <U>(callbackfn: (previousValue: U, currentValue: string, currentIndex: number, array: string[]) => U, initialValue: U): U; }' has signatures, but none of those signatures are compatible with each other.
==== tests/cases/compiler/unionOfClassCalls.ts (1 errors) ====
// from https://github.com/microsoft/TypeScript/issues/30717
declare class Test<T> {
obj: T;
get<K extends keyof T>(k: K): T[K];
}
interface A { t: "A" }
interface B { t: "B" }
declare const tmp: Test<A> | Test<B>;
switch (tmp.get('t')) {
case 'A': break;
case 'B': break;
}
// from https://github.com/microsoft/TypeScript/issues/36390
const arr: number[] | string[] = []; // Works with Array<number | string>
const arr1: number[] = [];
const arr2: string[] = [];
arr.map((a: number | string, index: number) => {
return index
})
// This case still doesn't work because `reduce` has multiple overloads :(
arr.reduce((acc: Array<string>, a: number | string, index: number) => {
~~~~~~
!!! error TS2349: This expression is not callable.
!!! error TS2349: Each member of the union type '{ (callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: number[]) => number): number; (callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: number[]) => number, initialValue: number): number; <U>(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: number[]) => U, initialValue: U): U; } | { (callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string): string; (callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string, initialValue: string): string; <U>(callbackfn: (previousValue: U, currentValue: string, currentIndex: number, array: string[]) => U, initialValue: U): U; }' has signatures, but none of those signatures are compatible with each other.
return []
}, [])
arr.forEach((a: number | string, index: number) => {
return index
})
arr1.map((a: number, index: number) => {
return index
})
arr1.reduce((acc: number[], a: number, index: number) => {
return [a]
}, [])
arr1.forEach((a: number, index: number) => {
return index
})
arr2.map((a: string, index: number) => {
return index
})
arr2.reduce((acc: string[], a: string, index: number) => {
return []
}, [])
arr2.forEach((a: string, index: number) => {
return index
})
// from https://github.com/microsoft/TypeScript/issues/36307
declare class Foo {
doThing(): Promise<this>
}
declare class Bar extends Foo {
bar: number;
}
declare class Baz extends Foo {
baz: number;
}
declare var a: Bar | Baz;
// note, you must annotate `result` for now
a.doThing().then((result: Bar | Baz) => {
// whatever
});

View File

@ -64,7 +64,7 @@ arr.map((a: number | string, index: number) => {
// This case still doesn't work because `reduce` has multiple overloads :(
arr.reduce((acc: Array<string>, a: number | string, index: number) => {
>arr.reduce((acc: Array<string>, a: number | string, index: number) => { return []}, []) : any
>arr.reduce((acc: Array<string>, a: number | string, index: number) => { return []}, []) : never[]
>arr.reduce : { (callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: number[]) => number): number; (callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: number[]) => number, initialValue: number): number; <U>(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: number[]) => U, initialValue: U): U; } | { (callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string): string; (callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string, initialValue: string): string; <U>(callbackfn: (previousValue: U, currentValue: string, currentIndex: number, array: string[]) => U, initialValue: U): U; }
>arr : number[] | string[]
>reduce : { (callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: number[]) => number): number; (callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: number[]) => number, initialValue: number): number; <U>(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: number[]) => U, initialValue: U): U; } | { (callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string): string; (callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string, initialValue: string): string; <U>(callbackfn: (previousValue: U, currentValue: string, currentIndex: number, array: string[]) => U, initialValue: U): U; }

View File

@ -0,0 +1,26 @@
// @target: es6
interface Fizz {
id: number;
fizz: string;
}
interface Buzz {
id: number;
buzz: string;
}
([] as Fizz[] | Buzz[]).filter(item => item.id < 5);
([] as Fizz[] | readonly Buzz[]).filter(item => item.id < 5);
([] as Fizz[] | Buzz[]).find(item => item);
declare function isFizz(x: unknown): x is Fizz;
([] as Fizz[] | Buzz[]).find(isFizz);
declare function isBuzz(x: unknown): x is Buzz;
([] as Fizz[] | Buzz[]).find(isBuzz);
([] as Fizz[] | Buzz[]).every(item => item.id < 5);
([] as Fizz[] | Buzz[]).reduce(item => item);
([] as [Fizz] | readonly [Buzz?]).filter(item => item?.id < 5);