Skip to content

Commit

Permalink
Add fallback logic for generating signatures for unions of array memb…
Browse files Browse the repository at this point in the history
…ers (#53489)
  • Loading branch information
weswigham authored May 16, 2023
1 parent 58f0300 commit b0c8020
Show file tree
Hide file tree
Showing 9 changed files with 1,217 additions and 2,508 deletions.
31 changes: 30 additions & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Loading

0 comments on commit b0c8020

Please sign in to comment.