Skip to content
31 changes: 22 additions & 9 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16738,7 +16738,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
const type = elementTypes[i];
const flags = target.elementFlags[i];
if (flags & ElementFlags.Variadic) {
if (type.flags & TypeFlags.InstantiableNonPrimitive || isGenericMappedType(type)) {
if (type.flags & TypeFlags.InstantiableNonPrimitive || everyContainedType(type, isGenericMappedType)) {
// Generic variadic elements stay as they are.
addElement(type, ElementFlags.Variadic, target.labeledElementDeclarations?.[i]);
}
Expand Down Expand Up @@ -30246,13 +30246,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {

function getTypeOfPropertyOfContextualType(type: Type, name: __String, nameType?: Type) {
return mapType(type, t => {
if (isGenericMappedType(t) && !t.declaration.nameType) {
const constraint = getConstraintTypeFromMappedType(t);
const constraintOfConstraint = getBaseConstraintOfType(constraint) || constraint;
const propertyNameType = nameType || getStringLiteralType(unescapeLeadingUnderscores(name));
if (isTypeAssignableTo(propertyNameType, constraintOfConstraint)) {
return substituteIndexedMappedType(t, propertyNameType);
}
if (everyContainedType(t, t => isGenericMappedType(t) && !t.declaration.nameType)) {
const newTypes = mapDefined(t.flags & TypeFlags.Intersection ? (t as IntersectionType).types : [t], t => {
const mappedType = t as MappedType;
const constraint = getConstraintTypeFromMappedType(mappedType);
const constraintOfConstraint = getBaseConstraintOfType(constraint) || constraint;
const propertyNameType = nameType || getStringLiteralType(unescapeLeadingUnderscores(name));
if (isTypeAssignableTo(propertyNameType, constraintOfConstraint)) {
return substituteIndexedMappedType(mappedType, propertyNameType);
}
});
return newTypes.length ? getIntersectionType(newTypes) : undefined;
}
else if (t.flags & TypeFlags.StructuredType) {
const prop = getPropertyOfType(t, name);
Expand Down Expand Up @@ -30486,6 +30490,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
);
}

function getApparentTypeOfInstantiatedContextualType(type: Type) {
return getObjectFlags(type) & ObjectFlags.Mapped ? type : getApparentType(type);
}

// Return the contextual type for a given expression node. During overload resolution, a contextual type may temporarily
// be "pushed" onto a node using the contextualType property.
function getApparentTypeOfContextualType(node: Expression | MethodDeclaration, contextFlags: ContextFlags | undefined): Type | undefined {
Expand All @@ -30500,7 +30508,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// That would evaluate mapped types with array or tuple type constraints too eagerly
// and thus it would prevent `getTypeOfPropertyOfContextualType` from obtaining per-position contextual type for elements of array literal expressions.
// Apparent type of other mapped types is already the mapped type itself so we can just avoid calling `getApparentType` here for all mapped types.
t => getObjectFlags(t) & ObjectFlags.Mapped ? t : getApparentType(t),
t => {
if (t.flags & TypeFlags.Intersection) {
return getIntersectionType(map((t as IntersectionType).types, getApparentTypeOfInstantiatedContextualType));
}
return getApparentTypeOfInstantiatedContextualType(t);
},
/*noReductions*/ true,
);
return apparentType.flags & TypeFlags.Union && isObjectLiteralExpression(node) ? discriminateContextualTypeByObjectMembers(node, apparentType as UnionType) :
Expand Down
266 changes: 266 additions & 0 deletions tests/baselines/reference/reverseMappedIntersectionInference.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,266 @@
//// [tests/cases/compiler/reverseMappedIntersectionInference.ts] ////

=== reverseMappedIntersectionInference.ts ===
type Results<T> = {
>Results : Symbol(Results, Decl(reverseMappedIntersectionInference.ts, 0, 0))
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 0, 13))

[K in keyof T]: {
>K : Symbol(K, Decl(reverseMappedIntersectionInference.ts, 1, 3))
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 0, 13))

data: T[K];
>data : Symbol(data, Decl(reverseMappedIntersectionInference.ts, 1, 19))
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 0, 13))
>K : Symbol(K, Decl(reverseMappedIntersectionInference.ts, 1, 3))

onSuccess: (data: T[K]) => void;
>onSuccess : Symbol(onSuccess, Decl(reverseMappedIntersectionInference.ts, 2, 15))
>data : Symbol(data, Decl(reverseMappedIntersectionInference.ts, 3, 16))
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 0, 13))
>K : Symbol(K, Decl(reverseMappedIntersectionInference.ts, 1, 3))

};
};

type Errors<E> = {
>Errors : Symbol(Errors, Decl(reverseMappedIntersectionInference.ts, 5, 2))
>E : Symbol(E, Decl(reverseMappedIntersectionInference.ts, 7, 12))

[K in keyof E]: {
>K : Symbol(K, Decl(reverseMappedIntersectionInference.ts, 8, 3))
>E : Symbol(E, Decl(reverseMappedIntersectionInference.ts, 7, 12))

error: E[K];
>error : Symbol(error, Decl(reverseMappedIntersectionInference.ts, 8, 19))
>E : Symbol(E, Decl(reverseMappedIntersectionInference.ts, 7, 12))
>K : Symbol(K, Decl(reverseMappedIntersectionInference.ts, 8, 3))

onError: (data: E[K]) => void;
>onError : Symbol(onError, Decl(reverseMappedIntersectionInference.ts, 9, 16))
>data : Symbol(data, Decl(reverseMappedIntersectionInference.ts, 10, 14))
>E : Symbol(E, Decl(reverseMappedIntersectionInference.ts, 7, 12))
>K : Symbol(K, Decl(reverseMappedIntersectionInference.ts, 8, 3))

};
};

declare function withKeyedObj<T, E>(
>withKeyedObj : Symbol(withKeyedObj, Decl(reverseMappedIntersectionInference.ts, 12, 2))
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 14, 30))
>E : Symbol(E, Decl(reverseMappedIntersectionInference.ts, 14, 32))

arg: Results<T> & Errors<E>
>arg : Symbol(arg, Decl(reverseMappedIntersectionInference.ts, 14, 36))
>Results : Symbol(Results, Decl(reverseMappedIntersectionInference.ts, 0, 0))
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 14, 30))
>Errors : Symbol(Errors, Decl(reverseMappedIntersectionInference.ts, 5, 2))
>E : Symbol(E, Decl(reverseMappedIntersectionInference.ts, 14, 32))

): [T, E];
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 14, 30))
>E : Symbol(E, Decl(reverseMappedIntersectionInference.ts, 14, 32))

const res = withKeyedObj({
>res : Symbol(res, Decl(reverseMappedIntersectionInference.ts, 18, 5))
>withKeyedObj : Symbol(withKeyedObj, Decl(reverseMappedIntersectionInference.ts, 12, 2))

a: {
>a : Symbol(a, Decl(reverseMappedIntersectionInference.ts, 18, 26))

data: "foo",
>data : Symbol(data, Decl(reverseMappedIntersectionInference.ts, 19, 6))

onSuccess: (dataArg) => {
>onSuccess : Symbol(onSuccess, Decl(reverseMappedIntersectionInference.ts, 20, 16))
>dataArg : Symbol(dataArg, Decl(reverseMappedIntersectionInference.ts, 21, 16))

dataArg;
>dataArg : Symbol(dataArg, Decl(reverseMappedIntersectionInference.ts, 21, 16))

},
error: 404,
>error : Symbol(error, Decl(reverseMappedIntersectionInference.ts, 23, 6))

onError: (errorArg) => {
>onError : Symbol(onError, Decl(reverseMappedIntersectionInference.ts, 24, 15))
>errorArg : Symbol(errorArg, Decl(reverseMappedIntersectionInference.ts, 25, 14))

errorArg;
>errorArg : Symbol(errorArg, Decl(reverseMappedIntersectionInference.ts, 25, 14))

},
},
b: {
>b : Symbol(b, Decl(reverseMappedIntersectionInference.ts, 28, 4))

data: true,
>data : Symbol(data, Decl(reverseMappedIntersectionInference.ts, 29, 6))

onSuccess: (dataArg) => {
>onSuccess : Symbol(onSuccess, Decl(reverseMappedIntersectionInference.ts, 30, 15))
>dataArg : Symbol(dataArg, Decl(reverseMappedIntersectionInference.ts, 31, 16))

dataArg;
>dataArg : Symbol(dataArg, Decl(reverseMappedIntersectionInference.ts, 31, 16))

},
error: 500,
>error : Symbol(error, Decl(reverseMappedIntersectionInference.ts, 33, 6))

onError: (errorArg) => {
>onError : Symbol(onError, Decl(reverseMappedIntersectionInference.ts, 34, 15))
>errorArg : Symbol(errorArg, Decl(reverseMappedIntersectionInference.ts, 35, 14))

errorArg;
>errorArg : Symbol(errorArg, Decl(reverseMappedIntersectionInference.ts, 35, 14))

},
},
});

declare function withTuples<T extends any[], E extends any[]>(
>withTuples : Symbol(withTuples, Decl(reverseMappedIntersectionInference.ts, 39, 3))
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 41, 28))
>E : Symbol(E, Decl(reverseMappedIntersectionInference.ts, 41, 44))

arg: [...(Results<T> & Errors<E>)]
>arg : Symbol(arg, Decl(reverseMappedIntersectionInference.ts, 41, 62))
>Results : Symbol(Results, Decl(reverseMappedIntersectionInference.ts, 0, 0))
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 41, 28))
>Errors : Symbol(Errors, Decl(reverseMappedIntersectionInference.ts, 5, 2))
>E : Symbol(E, Decl(reverseMappedIntersectionInference.ts, 41, 44))

): [T, E];
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 41, 28))
>E : Symbol(E, Decl(reverseMappedIntersectionInference.ts, 41, 44))

const res2 = withTuples([
>res2 : Symbol(res2, Decl(reverseMappedIntersectionInference.ts, 45, 5))
>withTuples : Symbol(withTuples, Decl(reverseMappedIntersectionInference.ts, 39, 3))
{
data: "foo",
>data : Symbol(data, Decl(reverseMappedIntersectionInference.ts, 46, 3))

onSuccess: (dataArg) => {
>onSuccess : Symbol(onSuccess, Decl(reverseMappedIntersectionInference.ts, 47, 16))
>dataArg : Symbol(dataArg, Decl(reverseMappedIntersectionInference.ts, 48, 16))

dataArg;
>dataArg : Symbol(dataArg, Decl(reverseMappedIntersectionInference.ts, 48, 16))

},
error: 404,
>error : Symbol(error, Decl(reverseMappedIntersectionInference.ts, 50, 6))

onError: (errorArg) => {
>onError : Symbol(onError, Decl(reverseMappedIntersectionInference.ts, 51, 15))
>errorArg : Symbol(errorArg, Decl(reverseMappedIntersectionInference.ts, 52, 14))

errorArg;
>errorArg : Symbol(errorArg, Decl(reverseMappedIntersectionInference.ts, 52, 14))

},
},
{
data: true,
>data : Symbol(data, Decl(reverseMappedIntersectionInference.ts, 56, 3))

onSuccess: (dataArg) => {
>onSuccess : Symbol(onSuccess, Decl(reverseMappedIntersectionInference.ts, 57, 15))
>dataArg : Symbol(dataArg, Decl(reverseMappedIntersectionInference.ts, 58, 16))

dataArg;
>dataArg : Symbol(dataArg, Decl(reverseMappedIntersectionInference.ts, 58, 16))

},
error: 500,
>error : Symbol(error, Decl(reverseMappedIntersectionInference.ts, 60, 6))

onError: (errorArg) => {
>onError : Symbol(onError, Decl(reverseMappedIntersectionInference.ts, 61, 15))
>errorArg : Symbol(errorArg, Decl(reverseMappedIntersectionInference.ts, 62, 14))

errorArg;
>errorArg : Symbol(errorArg, Decl(reverseMappedIntersectionInference.ts, 62, 14))

},
},
]);

type Tuple<T> = readonly [T, ...T[]];
>Tuple : Symbol(Tuple, Decl(reverseMappedIntersectionInference.ts, 66, 3))
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 68, 11))
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 68, 11))
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 68, 11))

declare function withTuplesConstraints<T extends Tuple<any>, E extends Tuple<any>>(
>withTuplesConstraints : Symbol(withTuplesConstraints, Decl(reverseMappedIntersectionInference.ts, 68, 37))
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 70, 39))
>Tuple : Symbol(Tuple, Decl(reverseMappedIntersectionInference.ts, 66, 3))
>E : Symbol(E, Decl(reverseMappedIntersectionInference.ts, 70, 60))
>Tuple : Symbol(Tuple, Decl(reverseMappedIntersectionInference.ts, 66, 3))

arg: Results<T> & Errors<E>
>arg : Symbol(arg, Decl(reverseMappedIntersectionInference.ts, 70, 83))
>Results : Symbol(Results, Decl(reverseMappedIntersectionInference.ts, 0, 0))
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 70, 39))
>Errors : Symbol(Errors, Decl(reverseMappedIntersectionInference.ts, 5, 2))
>E : Symbol(E, Decl(reverseMappedIntersectionInference.ts, 70, 60))

): [T, E];
>T : Symbol(T, Decl(reverseMappedIntersectionInference.ts, 70, 39))
>E : Symbol(E, Decl(reverseMappedIntersectionInference.ts, 70, 60))

const res3 = withTuplesConstraints([
>res3 : Symbol(res3, Decl(reverseMappedIntersectionInference.ts, 74, 5))
>withTuplesConstraints : Symbol(withTuplesConstraints, Decl(reverseMappedIntersectionInference.ts, 68, 37))
{
data: "foo",
>data : Symbol(data, Decl(reverseMappedIntersectionInference.ts, 75, 3))

onSuccess: (dataArg) => {
>onSuccess : Symbol(onSuccess, Decl(reverseMappedIntersectionInference.ts, 76, 16))
>dataArg : Symbol(dataArg, Decl(reverseMappedIntersectionInference.ts, 77, 16))

dataArg;
>dataArg : Symbol(dataArg, Decl(reverseMappedIntersectionInference.ts, 77, 16))

},
error: 404,
>error : Symbol(error, Decl(reverseMappedIntersectionInference.ts, 79, 6))

onError: (errorArg) => {
>onError : Symbol(onError, Decl(reverseMappedIntersectionInference.ts, 80, 15))
>errorArg : Symbol(errorArg, Decl(reverseMappedIntersectionInference.ts, 81, 14))

errorArg;
>errorArg : Symbol(errorArg, Decl(reverseMappedIntersectionInference.ts, 81, 14))

},
},
{
data: true,
>data : Symbol(data, Decl(reverseMappedIntersectionInference.ts, 85, 3))

onSuccess: (dataArg) => {
>onSuccess : Symbol(onSuccess, Decl(reverseMappedIntersectionInference.ts, 86, 15))
>dataArg : Symbol(dataArg, Decl(reverseMappedIntersectionInference.ts, 87, 16))

dataArg;
>dataArg : Symbol(dataArg, Decl(reverseMappedIntersectionInference.ts, 87, 16))

},
error: 500,
>error : Symbol(error, Decl(reverseMappedIntersectionInference.ts, 89, 6))

onError: (errorArg) => {
>onError : Symbol(onError, Decl(reverseMappedIntersectionInference.ts, 90, 15))
>errorArg : Symbol(errorArg, Decl(reverseMappedIntersectionInference.ts, 91, 14))

errorArg;
>errorArg : Symbol(errorArg, Decl(reverseMappedIntersectionInference.ts, 91, 14))

},
},
]);
Loading