Skip to content

Commit ced3cc1

Browse files
committed
refactor
1 parent 22ddecc commit ced3cc1

22 files changed

+855
-704
lines changed

src/compiler/checker.ts

Lines changed: 51 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -2108,7 +2108,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
21082108
var unreachableNeverType = createIntrinsicType(TypeFlags.Never, "never", /*objectFlags*/ undefined, "unreachable");
21092109
var nonPrimitiveType = createIntrinsicType(TypeFlags.NonPrimitive, "object");
21102110
var stringOrNumberType = getUnionType([stringType, numberType]);
2111-
var stringNumberSymbolType = getUnionType([stringType, numberType, esSymbolType]) as UnionType;
2111+
var stringNumberSymbolType = getUnionType([stringType, numberType, esSymbolType]);
21122112
var numberOrBigIntType = getUnionType([numberType, bigintType]);
21132113
var templateConstraintType = getUnionType([stringType, numberType, booleanType, bigintType, nullType, undefinedType]) as UnionType;
21142114
var numericStringType = getTemplateLiteralType(["", ""], [numberType]); // The `${number}` type
@@ -2144,9 +2144,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
21442144
var unknownEmptyObjectType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, emptyArray);
21452145
var unknownUnionType = strictNullChecks ? getUnionType([undefinedType, nullType, unknownEmptyObjectType]) : unknownType;
21462146

2147-
var allKeysUnknownType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, map(stringNumberSymbolType.types, t => createIndexInfo(t, unknownType, /*isReadonly*/ false))); // { [k: PropertyKey]: unknown }
2148-
var allKeysAllKeysUnknownType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, map(stringNumberSymbolType.types, t => createIndexInfo(t, allKeysUnknownType, /*isReadonly*/ false))); // { [k: PropertyKey]: { [k: PropertyKey]: unknown } }
2149-
21502147
var emptyGenericType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, emptyArray) as ObjectType as GenericType;
21512148
emptyGenericType.instantiations = new Map<string, TypeReference>();
21522149

@@ -26441,18 +26438,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2644126438
const templateType = getTemplateTypeFromMappedType(target);
2644226439
const inference = createInferenceInfo(inferenceTarget);
2644326440
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;
26441+
return getTypeFromInference(inference) || unknownType;
2645626442
}
2645726443

2645826444
function inferReverseMappedType(source: Type, target: MappedType, constraint: IndexType): Type | undefined {
@@ -26521,7 +26507,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2652126507
function getTypeFromInference(inference: InferenceInfo) {
2652226508
return inference.candidates ? getUnionType(inference.candidates, UnionReduction.Subtype) :
2652326509
inference.contraCandidates ? getIntersectionType(inference.contraCandidates) :
26524-
undefined;
26510+
getAggregateInference(inference);
2652526511
}
2652626512

2652726513
function hasSkipDirectInferenceFlag(node: Node) {
@@ -27568,6 +27554,52 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2756827554
return getWidenedType(unwidenedType);
2756927555
}
2757027556

27557+
function getAggregateInference(inference: InferenceInfo, constraintType?: Type, compareTypes?: TypeComparer, mapper?: TypeMapper | undefined): Type | undefined {
27558+
if (!inference.indexes) {
27559+
return undefined;
27560+
}
27561+
const typeEraser = createTypeEraser([inference.typeParameter.flags & TypeFlags.IndexedAccess ? (inference.typeParameter as IndexedAccessType).objectType : inference.typeParameter]);
27562+
const aggregateInference = instantiateType(getIntersectionType(inference.indexes), mapper ? mergeTypeMappers(typeEraser, mapper) : typeEraser);
27563+
if (getReducedType(aggregateInference).flags & TypeFlags.Never) {
27564+
// `never` inference isn't that useful of an inference given its assignable to every other type
27565+
return undefined;
27566+
}
27567+
if (!constraintType || (compareTypes ??= compareTypesAssignable)(aggregateInference, getTypeWithThisArgument(constraintType, aggregateInference))) {
27568+
return aggregateInference;
27569+
}
27570+
if (constraintType.flags & TypeFlags.Union) {
27571+
const discriminantProps = findDiscriminantProperties(getPropertiesOfType(aggregateInference), constraintType);
27572+
if (discriminantProps) {
27573+
let match: Type | undefined;
27574+
findDiscriminant:
27575+
for (const p of discriminantProps) {
27576+
const candidatePropType = getTypeOfPropertyOfType(aggregateInference, p.escapedName);
27577+
for (const type of (constraintType as UnionType).types) {
27578+
const propType = getTypeOfPropertyOfType(type, p.escapedName);
27579+
if (propType && candidatePropType && isTypeAssignableTo(candidatePropType, propType)) {
27580+
if (match && match !== type) {
27581+
match = undefined;
27582+
break findDiscriminant;
27583+
}
27584+
else {
27585+
match = type;
27586+
}
27587+
}
27588+
}
27589+
}
27590+
if (match) {
27591+
const combinedType = getSpreadType(match, aggregateInference, /*symbol*/ undefined, /*propegatedFlags*/ 0, /*readonly*/ false);
27592+
if (compareTypes(combinedType, getTypeWithThisArgument(constraintType, combinedType))) {
27593+
return combinedType;
27594+
}
27595+
}
27596+
}
27597+
}
27598+
// if the aggregate inference isn't assignable to the constraint return undefined
27599+
// this way the compiler keeps preferring the default type
27600+
return undefined;
27601+
}
27602+
2757127603
function getInferredType(context: InferenceContext, index: number): Type {
2757227604
const inference = context.inferences[index];
2757327605
if (!inference.inferredType) {
@@ -27593,51 +27625,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2759327625
fallbackType = preferCovariantType ? inferredContravariantType : inferredCovariantType;
2759427626
}
2759527627
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;
27628+
const instantiatedConstraint = instantiateType(getConstraintOfTypeParameter(inference.typeParameter), context.nonFixingMapper);
27629+
inferredType = getAggregateInference(inference, instantiatedConstraint, context.compareTypes, context.nonFixingMapper);
2764127630
}
2764227631
else if (context.flags & InferenceFlags.NoDefault) {
2764327632
// 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)