Skip to content

Commit

Permalink
Infer intersected reverse mapped types
Browse files Browse the repository at this point in the history
  • Loading branch information
Andarist committed Jan 2, 2023
1 parent 747172e commit ef2fba1
Show file tree
Hide file tree
Showing 4 changed files with 452 additions and 8 deletions.
20 changes: 12 additions & 8 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15688,7 +15688,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 @@ -28416,13 +28416,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
188 changes: 188 additions & 0 deletions tests/baselines/reference/reverseMappedIntersectionInference.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
=== tests/cases/compiler/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))

},
},
]);

Loading

0 comments on commit ef2fba1

Please sign in to comment.