Skip to content

Commit b0c8020

Browse files
authored
Add fallback logic for generating signatures for unions of array members (#53489)
1 parent 58f0300 commit b0c8020

9 files changed

+1217
-2508
lines changed

src/compiler/checker.ts

+30-1
Original file line numberDiff line numberDiff line change
@@ -14262,7 +14262,36 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1426214262
* maps primitive types and type parameters are to their apparent types.
1426314263
*/
1426414264
function getSignaturesOfType(type: Type, kind: SignatureKind): readonly Signature[] {
14265-
return getSignaturesOfStructuredType(getReducedApparentType(type), kind);
14265+
const result = getSignaturesOfStructuredType(getReducedApparentType(type), kind);
14266+
if (kind === SignatureKind.Call && !length(result) && type.flags & TypeFlags.Union) {
14267+
if ((type as UnionType).arrayFallbackSignatures) {
14268+
return (type as UnionType).arrayFallbackSignatures!;
14269+
}
14270+
// If the union is all different instantiations of a member of the global array type...
14271+
let memberName: __String;
14272+
if (everyType(type, t => !!t.symbol?.parent && isArrayOrTupleSymbol(t.symbol.parent) && (!memberName ? (memberName = t.symbol.escapedName, true) : memberName === t.symbol.escapedName))) {
14273+
// Transform the type from `(A[] | B[])["member"]` to `(A | B)[]["member"]` (since we pretend array is covariant anyway)
14274+
const arrayArg = mapType(type, t => getMappedType((isReadonlyArraySymbol(t.symbol.parent) ? globalReadonlyArrayType : globalArrayType).typeParameters![0], (t as AnonymousType).mapper!));
14275+
const arrayType = createArrayType(arrayArg, someType(type, t => isReadonlyArraySymbol(t.symbol.parent)));
14276+
return (type as UnionType).arrayFallbackSignatures = getSignaturesOfType(getTypeOfPropertyOfType(arrayType, memberName!)!, kind);
14277+
}
14278+
(type as UnionType).arrayFallbackSignatures = result;
14279+
}
14280+
return result;
14281+
}
14282+
14283+
function isArrayOrTupleSymbol(symbol: Symbol | undefined) {
14284+
if (!symbol || !globalArrayType.symbol || !globalReadonlyArrayType.symbol) {
14285+
return false;
14286+
}
14287+
return !!getSymbolIfSameReference(symbol, globalArrayType.symbol) || !!getSymbolIfSameReference(symbol, globalReadonlyArrayType.symbol);
14288+
}
14289+
14290+
function isReadonlyArraySymbol(symbol: Symbol | undefined) {
14291+
if (!symbol || !globalReadonlyArrayType.symbol) {
14292+
return false;
14293+
}
14294+
return !!getSymbolIfSameReference(symbol, globalReadonlyArrayType.symbol);
1426614295
}
1426714296

1426814297
function findIndexInfo(indexInfos: readonly IndexInfo[], keyType: Type) {

src/compiler/types.ts

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

64706472
export interface IntersectionType extends UnionOrIntersectionType {

0 commit comments

Comments
 (0)