Skip to content

Commit d603445

Browse files
committed
refactor
1 parent 22ddecc commit d603445

22 files changed

+854
-700
lines changed

src/compiler/checker.ts

Lines changed: 50 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -26441,18 +26441,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2644126441
const templateType = getTemplateTypeFromMappedType(target);
2644226442
const inference = createInferenceInfo(inferenceTarget);
2644326443
inferTypes([inference], sourceType, templateType);
26444-
const inferredType = getTypeFromInference(inference);
26445-
if (inferredType) {
26446-
return inferredType;
26447-
}
26448-
if (inference.indexes) {
26449-
const eraseSelfMapper = makeArrayTypeMapper([constraint.type, typeParameter], [allKeysAllKeysUnknownType, stringNumberSymbolType]);
26450-
const aggregateInference = instantiateType(getIntersectionType(inference.indexes), eraseSelfMapper);
26451-
if (!(getReducedType(aggregateInference).flags & TypeFlags.Never)) {
26452-
return aggregateInference;
26453-
}
26454-
}
26455-
return unknownType;
26444+
return getTypeFromInference(inference) || unknownType;
2645626445
}
2645726446

2645826447
function inferReverseMappedType(source: Type, target: MappedType, constraint: IndexType): Type | undefined {
@@ -26521,7 +26510,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2652126510
function getTypeFromInference(inference: InferenceInfo) {
2652226511
return inference.candidates ? getUnionType(inference.candidates, UnionReduction.Subtype) :
2652326512
inference.contraCandidates ? getIntersectionType(inference.contraCandidates) :
26524-
undefined;
26513+
getAggregateInference(inference);
2652526514
}
2652626515

2652726516
function hasSkipDirectInferenceFlag(node: Node) {
@@ -27568,6 +27557,52 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2756827557
return getWidenedType(unwidenedType);
2756927558
}
2757027559

27560+
function getAggregateInference(inference: InferenceInfo, constraintType?: Type, compareTypes?: TypeComparer, mapper?: TypeMapper | undefined): Type | undefined {
27561+
if (!inference.indexes) {
27562+
return undefined;
27563+
}
27564+
const typeEraser = createTypeEraser([inference.typeParameter.flags & TypeFlags.IndexedAccess ? (inference.typeParameter as IndexedAccessType).objectType : inference.typeParameter]);
27565+
const aggregateInference = instantiateType(getIntersectionType(inference.indexes), mapper ? mergeTypeMappers(typeEraser, mapper) : typeEraser);
27566+
if (getReducedType(aggregateInference).flags & TypeFlags.Never) {
27567+
// `never` inference isn't that useful of an inference given its assignable to every other type
27568+
return undefined;
27569+
}
27570+
if (!constraintType || (compareTypes ??= compareTypesAssignable)(aggregateInference, getTypeWithThisArgument(constraintType, aggregateInference))) {
27571+
return aggregateInference;
27572+
}
27573+
if (constraintType.flags & TypeFlags.Union) {
27574+
const discriminantProps = findDiscriminantProperties(getPropertiesOfType(aggregateInference), constraintType);
27575+
if (discriminantProps) {
27576+
let match: Type | undefined;
27577+
findDiscriminant:
27578+
for (const p of discriminantProps) {
27579+
const candidatePropType = getTypeOfPropertyOfType(aggregateInference, p.escapedName);
27580+
for (const type of (constraintType as UnionType).types) {
27581+
const propType = getTypeOfPropertyOfType(type, p.escapedName);
27582+
if (propType && candidatePropType && isTypeAssignableTo(candidatePropType, propType)) {
27583+
if (match && match !== type) {
27584+
match = undefined;
27585+
break findDiscriminant;
27586+
}
27587+
else {
27588+
match = type;
27589+
}
27590+
}
27591+
}
27592+
}
27593+
if (match) {
27594+
const combinedType = getSpreadType(match, aggregateInference, /*symbol*/ undefined, /*propegatedFlags*/ 0, /*readonly*/ false);
27595+
if (compareTypes(combinedType, getTypeWithThisArgument(constraintType, combinedType))) {
27596+
return combinedType;
27597+
}
27598+
}
27599+
}
27600+
}
27601+
// if the aggregate inference isn't assignable to the constraint return undefined
27602+
// this way the compiler keeps preferring the default type
27603+
return undefined;
27604+
}
27605+
2757127606
function getInferredType(context: InferenceContext, index: number): Type {
2757227607
const inference = context.inferences[index];
2757327608
if (!inference.inferredType) {
@@ -27593,51 +27628,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2759327628
fallbackType = preferCovariantType ? inferredContravariantType : inferredCovariantType;
2759427629
}
2759527630
else if (inference.indexes) {
27596-
const eraseSelfMapper = makeUnaryTypeMapper(inference.typeParameter, allKeysUnknownType);
27597-
let aggregateInference: Type | undefined = instantiateType(getIntersectionType(inference.indexes), mergeTypeMappers(eraseSelfMapper, context.nonFixingMapper));
27598-
if (getReducedType(aggregateInference).flags & TypeFlags.Never) {
27599-
// `never` inference isn't that useful of an inference given its assignable to every other type
27600-
aggregateInference = undefined;
27601-
}
27602-
const constraint = getConstraintOfTypeParameter(inference.typeParameter);
27603-
if (aggregateInference && constraint) {
27604-
const instantiatedConstraint = instantiateType(constraint, context.nonFixingMapper);
27605-
let assignableToConstraint = context.compareTypes(aggregateInference, getTypeWithThisArgument(instantiatedConstraint, aggregateInference));
27606-
if (!assignableToConstraint) {
27607-
if (instantiatedConstraint.flags & TypeFlags.Union) {
27608-
const discriminantProps = findDiscriminantProperties(getPropertiesOfType(aggregateInference), instantiatedConstraint);
27609-
if (discriminantProps) {
27610-
let match: Type | undefined;
27611-
findDiscriminant:
27612-
for (const p of discriminantProps) {
27613-
const candidatePropType = getTypeOfPropertyOfType(aggregateInference, p.escapedName);
27614-
for (const type of (instantiatedConstraint as UnionType).types) {
27615-
const propType = getTypeOfPropertyOfType(type, p.escapedName);
27616-
if (propType && candidatePropType && checkTypeAssignableTo(candidatePropType, propType, /*errorNode*/ undefined)) {
27617-
if (match && match !== type) {
27618-
match = undefined;
27619-
break findDiscriminant;
27620-
}
27621-
else {
27622-
match = type;
27623-
}
27624-
}
27625-
}
27626-
}
27627-
if (match) {
27628-
aggregateInference = getSpreadType(match, aggregateInference, /*symbol*/ undefined, /*propegatedFlags*/ 0, /*readonly*/ false);
27629-
assignableToConstraint = context.compareTypes(aggregateInference, getTypeWithThisArgument(instantiatedConstraint, aggregateInference));
27630-
}
27631-
}
27632-
}
27633-
if (!assignableToConstraint) {
27634-
// if the aggregate inference isn't assignable to the constraint clear it out
27635-
// this way the compiler keeps preferring the default type
27636-
aggregateInference = undefined;
27637-
}
27638-
}
27639-
}
27640-
inferredType = aggregateInference;
27631+
const instantiatedConstraint = instantiateType(getConstraintOfTypeParameter(inference.typeParameter), context.nonFixingMapper);
27632+
inferredType = getAggregateInference(inference, instantiatedConstraint, context.compareTypes, context.nonFixingMapper);
2764127633
}
2764227634
else if (context.flags & InferenceFlags.NoDefault) {
2764327635
// We use silentNeverType as the wildcard that signals no inferences.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//// [tests/cases/compiler/typeInferenceAggregateFromIndicesInConditionalTypes1.ts] ////
2+
3+
=== typeInferenceAggregateFromIndicesInConditionalTypes1.ts ===
4+
type Foo = {
5+
>Foo : Symbol(Foo, Decl(typeInferenceAggregateFromIndicesInConditionalTypes1.ts, 0, 0))
6+
7+
a: string;
8+
>a : Symbol(a, Decl(typeInferenceAggregateFromIndicesInConditionalTypes1.ts, 0, 12))
9+
10+
b: number;
11+
>b : Symbol(b, Decl(typeInferenceAggregateFromIndicesInConditionalTypes1.ts, 1, 14))
12+
13+
c: boolean;
14+
>c : Symbol(c, Decl(typeInferenceAggregateFromIndicesInConditionalTypes1.ts, 2, 14))
15+
}
16+
17+
type AC<T> = T extends { a: (infer R extends Record<string, any>)["_a"]; c: (infer R)["_c"] } ? R : never;
18+
>AC : Symbol(AC, Decl(typeInferenceAggregateFromIndicesInConditionalTypes1.ts, 4, 1))
19+
>T : Symbol(T, Decl(typeInferenceAggregateFromIndicesInConditionalTypes1.ts, 6, 8))
20+
>T : Symbol(T, Decl(typeInferenceAggregateFromIndicesInConditionalTypes1.ts, 6, 8))
21+
>a : Symbol(a, Decl(typeInferenceAggregateFromIndicesInConditionalTypes1.ts, 6, 24))
22+
>R : Symbol(R, Decl(typeInferenceAggregateFromIndicesInConditionalTypes1.ts, 6, 34), Decl(typeInferenceAggregateFromIndicesInConditionalTypes1.ts, 6, 82))
23+
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
24+
>c : Symbol(c, Decl(typeInferenceAggregateFromIndicesInConditionalTypes1.ts, 6, 72))
25+
>R : Symbol(R, Decl(typeInferenceAggregateFromIndicesInConditionalTypes1.ts, 6, 34), Decl(typeInferenceAggregateFromIndicesInConditionalTypes1.ts, 6, 82))
26+
>R : Symbol(R, Decl(typeInferenceAggregateFromIndicesInConditionalTypes1.ts, 6, 34), Decl(typeInferenceAggregateFromIndicesInConditionalTypes1.ts, 6, 82))
27+
28+
type Result1 = AC<Foo>;
29+
>Result1 : Symbol(Result1, Decl(typeInferenceAggregateFromIndicesInConditionalTypes1.ts, 6, 106))
30+
>AC : Symbol(AC, Decl(typeInferenceAggregateFromIndicesInConditionalTypes1.ts, 4, 1))
31+
>Foo : Symbol(Foo, Decl(typeInferenceAggregateFromIndicesInConditionalTypes1.ts, 0, 0))
32+
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//// [tests/cases/compiler/typeInferenceAggregateFromIndicesInConditionalTypes1.ts] ////
2+
3+
=== typeInferenceAggregateFromIndicesInConditionalTypes1.ts ===
4+
type Foo = {
5+
>Foo : Foo
6+
> : ^^^
7+
8+
a: string;
9+
>a : string
10+
> : ^^^^^^
11+
12+
b: number;
13+
>b : number
14+
> : ^^^^^^
15+
16+
c: boolean;
17+
>c : boolean
18+
> : ^^^^^^^
19+
}
20+
21+
type AC<T> = T extends { a: (infer R extends Record<string, any>)["_a"]; c: (infer R)["_c"] } ? R : never;
22+
>AC : AC<T>
23+
> : ^^^^^
24+
>a : R["_a"]
25+
> : ^^^^^^^
26+
>c : R["_c"]
27+
> : ^^^^^^^
28+
29+
type Result1 = AC<Foo>;
30+
>Result1 : { _a: string; } & { _c: boolean; }
31+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
32+

tests/baselines/reference/typeInferenceIndexingUsingOtherTypeParameter1.symbols

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,20 @@ export const { name, values } = useController({
6969

7070
});
7171

72+
declare function fn1<T, U>(arg: T[keyof T & keyof U], u: U): T;
73+
>fn1 : Symbol(fn1, Decl(typeInferenceIndexingUsingOtherTypeParameter1.ts, 20, 3))
74+
>T : Symbol(T, Decl(typeInferenceIndexingUsingOtherTypeParameter1.ts, 22, 21))
75+
>U : Symbol(U, Decl(typeInferenceIndexingUsingOtherTypeParameter1.ts, 22, 23))
76+
>arg : Symbol(arg, Decl(typeInferenceIndexingUsingOtherTypeParameter1.ts, 22, 27))
77+
>T : Symbol(T, Decl(typeInferenceIndexingUsingOtherTypeParameter1.ts, 22, 21))
78+
>T : Symbol(T, Decl(typeInferenceIndexingUsingOtherTypeParameter1.ts, 22, 21))
79+
>U : Symbol(U, Decl(typeInferenceIndexingUsingOtherTypeParameter1.ts, 22, 23))
80+
>u : Symbol(u, Decl(typeInferenceIndexingUsingOtherTypeParameter1.ts, 22, 53))
81+
>U : Symbol(U, Decl(typeInferenceIndexingUsingOtherTypeParameter1.ts, 22, 23))
82+
>T : Symbol(T, Decl(typeInferenceIndexingUsingOtherTypeParameter1.ts, 22, 21))
83+
84+
const res1 = fn1("foo", { prop: 42 });
85+
>res1 : Symbol(res1, Decl(typeInferenceIndexingUsingOtherTypeParameter1.ts, 24, 5))
86+
>fn1 : Symbol(fn1, Decl(typeInferenceIndexingUsingOtherTypeParameter1.ts, 20, 3))
87+
>prop : Symbol(prop, Decl(typeInferenceIndexingUsingOtherTypeParameter1.ts, 24, 25))
88+

tests/baselines/reference/typeInferenceIndexingUsingOtherTypeParameter1.types

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,27 @@ export const { name, values } = useController({
6565

6666
});
6767

68+
declare function fn1<T, U>(arg: T[keyof T & keyof U], u: U): T;
69+
>fn1 : <T, U>(arg: T[keyof T & keyof U], u: U) => T
70+
> : ^ ^^ ^^ ^^ ^^ ^^ ^^^^^
71+
>arg : T[keyof T & keyof U]
72+
> : ^^^^^^^^^^^^^^^^^^^^
73+
>u : U
74+
> : ^
75+
76+
const res1 = fn1("foo", { prop: 42 });
77+
>res1 : { prop: "foo"; }
78+
> : ^^^^^^^^^^^^^^^^
79+
>fn1("foo", { prop: 42 }) : { prop: "foo"; }
80+
> : ^^^^^^^^^^^^^^^^
81+
>fn1 : <T, U>(arg: T[keyof T & keyof U], u: U) => T
82+
> : ^ ^^ ^^ ^^ ^^ ^^ ^^^^^
83+
>"foo" : "foo"
84+
> : ^^^^^
85+
>{ prop: 42 } : { prop: number; }
86+
> : ^^^^^^^^^^^^^^^^^
87+
>prop : number
88+
> : ^^^^^^
89+
>42 : 42
90+
> : ^^
91+

tests/baselines/reference/typeInferenceSelfIndexingTypeParameter1.errors.txt

Lines changed: 0 additions & 39 deletions
This file was deleted.

0 commit comments

Comments
 (0)