Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
3451575
Infer type parameters from indexes on those parameters
weswigham Nov 18, 2017
f5b208c
Greatly simplify partial inference type instantiation through use of …
weswigham Nov 22, 2017
ba064ac
Add many more tests showing current behaviors
weswigham Nov 22, 2017
93afc10
Discriminate partial inferences if not complete enough to satisfy con…
weswigham Dec 1, 2017
49e1961
Move case to prefered location
weswigham Dec 21, 2017
96772e5
Small refactor to reduce how many comparisons are performed
weswigham Dec 21, 2017
2e0c635
Infer reverse mapped types based on inferences made for its concrete …
Andarist Feb 28, 2023
7b8cf10
Merge remote-tracking branch 'origin/main' into infer-concrete-proper…
Andarist Apr 17, 2023
e7e4e70
Merge remote-tracking branch 'weswigham/index-combined-inferences' in…
Andarist Apr 17, 2023
d0e8b8b
update baselines, note: some are broken
Andarist Apr 17, 2023
e5d0ea8
use new `inference.indexes` in reverse mapped type inference
Andarist Apr 17, 2023
b0b2fcb
update reverse mapped baseline
Andarist Apr 18, 2023
7fe118a
Call `getActualTypeVariable` appropriately to fix inference for a tup…
Andarist Apr 18, 2023
50e6a0c
Avoid inferring an index under `InferencePriority.NakedTypeVariable`
Andarist Apr 18, 2023
4febb9c
always discard aggregate inference that is not assignable to the cons…
Andarist Apr 19, 2023
c2d4b0f
bring back the union discriminating logic
Andarist Apr 19, 2023
11b02d0
fixed incorrect indexed access in tests
Andarist Apr 19, 2023
97adac5
only use the aggregate inference when there are no other candidates
Andarist Apr 19, 2023
8ffcb94
do not collect index-based inferences from non-inferrable types
Andarist Apr 20, 2023
192d8b7
Merge remote-tracking branch 'origin/main' into infer-concrete-proper…
Andarist May 22, 2023
5fa585c
Merge remote-tracking branch 'origin/main' into infer-concrete-proper…
Andarist Jun 13, 2023
375c127
Merge remote-tracking branch 'origin/main' into infer-concrete-proper…
Andarist Aug 22, 2023
a62749c
Merge remote-tracking branch 'origin/main' into infer-concrete-proper…
Andarist Sep 15, 2024
2f86371
Merge remote-tracking branch 'origin/main' into infer-concrete-proper…
Andarist Sep 16, 2024
9825bcd
update baselines
Andarist Sep 16, 2024
46e280b
Merge remote-tracking branch 'origin/main' into infer-concrete-proper…
Andarist Nov 28, 2025
c90fb20
instantiate aggregate inference
Andarist Nov 30, 2025
2b580c8
experiment with `eraseSelfMapper`
Andarist Dec 1, 2025
a390703
experiment further
Andarist Dec 1, 2025
15eda09
drop unused code
Andarist Dec 1, 2025
e3f6b43
discard never aggregate inferences
Andarist Dec 2, 2025
1911406
prefer default
Andarist Dec 2, 2025
20d6feb
Merge remote-tracking branch 'origin/main' into infer-concrete-proper…
Andarist Dec 2, 2025
a554bbf
change condition for indexes gathering
Andarist Dec 2, 2025
22ddecc
simplify test
Andarist Dec 2, 2025
ced3cc1
refactor
Andarist Dec 2, 2025
a09f410
remove `PartialInference`
Andarist Dec 3, 2025
7bc77f1
add tests
Andarist Dec 3, 2025
097b8e6
Merge remote-tracking branch 'origin/main' into infer-concrete-proper…
Andarist Dec 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
experiment further
  • Loading branch information
Andarist committed Dec 1, 2025
commit a390703c1f4aecdd18fce7a7832cbb3c824f9057
28 changes: 20 additions & 8 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2304,6 +2304,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
var deferredGlobalBigIntType: ObjectType | undefined;
var deferredGlobalNaNSymbol: Symbol | undefined;
var deferredGlobalRecordSymbol: Symbol | undefined;
var deferredGlobalPartialInferenceSymbol: Symbol | undefined;
var deferredGlobalClassDecoratorContextType: GenericType | undefined;
var deferredGlobalClassMethodDecoratorContextType: GenericType | undefined;
var deferredGlobalClassGetterDecoratorContextType: GenericType | undefined;
Expand Down Expand Up @@ -17632,6 +17633,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return deferredGlobalRecordSymbol === unknownSymbol ? undefined : deferredGlobalRecordSymbol;
}

function getGlobalPartialInferenceSymbol(): Symbol | undefined {
deferredGlobalPartialInferenceSymbol ||= getGlobalTypeAliasSymbol("PartialInference" as __String, /*arity*/ 2, /*reportErrors*/ false) || unknownSymbol;
return deferredGlobalPartialInferenceSymbol === unknownSymbol ? undefined : deferredGlobalPartialInferenceSymbol;
}

/**
* Instantiates a global type that is generic with some element type, and returns that instantiation.
*/
Expand Down Expand Up @@ -26908,11 +26914,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (!inference.isFixed) {
// Instantiates instance of `type PartialInference<T, Keys extends string> = ({[K in Keys]: {[K1 in K]: T}})[Keys];`
// Where `T` is `source` and `Keys` is `target.indexType`
const inferenceTypeSymbol = getGlobalSymbol("PartialInference" as __String, SymbolFlags.Type, Diagnostics.Cannot_find_global_type_0);
const inferenceType = inferenceTypeSymbol && getDeclaredTypeOfSymbol(inferenceTypeSymbol);
if (inferenceType && inferenceType !== unknownType) {
const mapper = createTypeMapper(getSymbolLinks(inferenceTypeSymbol).typeParameters!, [source, (target as IndexedAccessType).indexType]);
inference.indexes = append(inference.indexes, instantiateType(inferenceType, mapper));
const partialInferenceTypeSymbol = getGlobalPartialInferenceSymbol();
if (partialInferenceTypeSymbol) {
if ((target as IndexedAccessType).indexType.flags & TypeFlags.Instantiable) {
const recordSymbol = getGlobalRecordSymbol();
if (recordSymbol) {
inference.indexes = append(inference.indexes, getTypeAliasInstantiation(recordSymbol, [(target as IndexedAccessType).indexType, source]));
}
}
else {
inference.indexes = append(inference.indexes, getTypeAliasInstantiation(partialInferenceTypeSymbol, [source, (target as IndexedAccessType).indexType]));
}
}
}
}
Expand Down Expand Up @@ -27590,7 +27602,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
fallbackType = preferCovariantType ? inferredContravariantType : inferredCovariantType;
}
else if (inference.indexes) {
let aggregateInference = getIntersectionType(inference.indexes);
const eraseSelfMapper = makeUnaryTypeMapper(inference.typeParameter, allKeysUnknownType);
let aggregateInference = instantiateType(getIntersectionType(inference.indexes), mergeTypeMappers(eraseSelfMapper, context.nonFixingMapper));
const constraint = getConstraintOfTypeParameter(inference.typeParameter);
if (constraint) {
const instantiatedConstraint = instantiateType(constraint, context.nonFixingMapper);
Expand Down Expand Up @@ -27620,8 +27633,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
}
}
const eraseSelfMapper = makeUnaryTypeMapper(inference.typeParameter, allKeysUnknownType);
inferredType = instantiateType(aggregateInference, mergeTypeMappers(eraseSelfMapper, context.nonFixingMapper));
inferredType = aggregateInference;
}
else if (context.flags & InferenceFlags.NoDefault) {
// We use silentNeverType as the wildcard that signals no inferences.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2692,7 +2692,7 @@
// | type ParameterDecorator = (target: Object, propertyKey: string | symbol | undefined, parameterIndex: number) => void
// | type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never
// | type Partial<T> = { [P in keyof T]?: T[P]; }
// | type PartialInference<T, Keys extends string> = { [K in Keys]: { [K1 in K]: T; }; }[Keys]
// | type PartialInference<T, Keys extends PropertyKey> = { [K in Keys]: { [K1 in K]: T; }; }[Keys]
// | type Pick<T, K extends keyof T> = { [P in K]: T[P]; }
// | interface Promise<T>
// | type PromiseConstructorLike = new <T>(executor: (resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void) => PromiseLike<T>
Expand Down Expand Up @@ -2873,7 +2873,7 @@
// | type ParameterDecorator = (target: Object, propertyKey: string | symbol | undefined, parameterIndex: number) => void
// | type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never
// | type Partial<T> = { [P in keyof T]?: T[P]; }
// | type PartialInference<T, Keys extends string> = { [K in Keys]: { [K1 in K]: T; }; }[Keys]
// | type PartialInference<T, Keys extends PropertyKey> = { [K in Keys]: { [K1 in K]: T; }; }[Keys]
// | type Pick<T, K extends keyof T> = { [P in K]: T[P]; }
// | interface Promise<T>
// | type PromiseConstructorLike = new <T>(executor: (resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void) => PromiseLike<T>
Expand Down Expand Up @@ -80663,8 +80663,8 @@
"kind": "space"
},
{
"text": "string",
"kind": "keyword"
"text": "PropertyKey",
"kind": "aliasName"
},
{
"text": ">",
Expand Down Expand Up @@ -90340,8 +90340,8 @@
"kind": "space"
},
{
"text": "string",
"kind": "keyword"
"text": "PropertyKey",
"kind": "aliasName"
},
{
"text": ">",
Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/inferingFromAny.types
Original file line number Diff line number Diff line change
Expand Up @@ -279,8 +279,8 @@ var a = f18(a);

var a = f19(a, a);
>a : any
>f19(a, a) : { [x: string]: any; }
> : ^^^^^^^^^^^^^^^^^^^^^
>f19(a, a) : Record<any, any>
> : ^^^^^^^^^^^^^^^^
>f19 : <T, K extends keyof T>(k: K, x: T[K]) => T
> : ^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^
>a : any
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,10 @@ declare function useController<
export const { name, values } = useController({
>name : "test"
> : ^^^^^^
>values : { test: string; }
> : ^^^^^^^^^^^^^^^^^
>useController({ name: "test", defaultValue: "",}) : { name: "test"; values: { test: string; }; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>values : Record<"test", string>
> : ^^^^^^^^^^^^^^^^^^^^^^
>useController({ name: "test", defaultValue: "",}) : { name: "test"; values: Record<"test", string>; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>useController : <TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = Path<TFieldValues>>(props: UseControllerProps<TFieldValues, TName>) => { name: TName; values: TFieldValues; }
> : ^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ ^^ ^^^^^
>{ name: "test", defaultValue: "",} : { name: "test"; defaultValue: string; }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
typeInferenceSelfIndexingTypeParameter1.ts(30,50): error TS2345: Argument of type 'Comparator<Record<"rangeStart", number>>' is not assignable to parameter of type 'Comparator<Record<"sourceOrder", number>>'.
Property 'rangeStart' is missing in type 'Record<"sourceOrder", number>' but required in type 'Record<"rangeStart", number>'.


==== typeInferenceSelfIndexingTypeParameter1.ts (1 errors) ====
type Comparator<T> = (a: T, b: T) => -1 | 0 | 1;

declare const createComparator: <T, K extends keyof T>(
property: K,
comparator: (a: T[K], b: T[K]) => 0 | 1 | -1,
) => Comparator<T>;

declare const concatComparators: <T,>(
c1: Comparator<T>,
c2: Comparator<T>,
...cRest: Comparator<T>[]
) => Comparator<T>;

declare const compareNumbers: (a: number, b: number) => 0 | 1 | -1;

declare class ModuleGraphConnection {
clone(): ModuleGraphConnection;
}

const bySourceOrder = createComparator("sourceOrder", compareNumbers);
const byRangeStart = createComparator("rangeStart", compareNumbers);

declare const references: {
connection: ModuleGraphConnection;
sourceOrder: number;
rangeStart: number | undefined;
defer?: boolean;
}[];

references.sort(concatComparators(bySourceOrder, byRangeStart));
~~~~~~~~~~~~
!!! error TS2345: Argument of type 'Comparator<Record<"rangeStart", number>>' is not assignable to parameter of type 'Comparator<Record<"sourceOrder", number>>'.
!!! error TS2345: Property 'rangeStart' is missing in type 'Record<"sourceOrder", number>' but required in type 'Record<"rangeStart", number>'.

Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,24 @@ type Comparator<T> = (a: T, b: T) => -1 | 0 | 1;
>b : Symbol(b, Decl(typeInferenceSelfIndexingTypeParameter1.ts, 0, 27))
>T : Symbol(T, Decl(typeInferenceSelfIndexingTypeParameter1.ts, 0, 16))

declare const createComparator: <T,>(
declare const createComparator: <T, K extends keyof T>(
>createComparator : Symbol(createComparator, Decl(typeInferenceSelfIndexingTypeParameter1.ts, 2, 13))
>T : Symbol(T, Decl(typeInferenceSelfIndexingTypeParameter1.ts, 2, 33))
>K : Symbol(K, Decl(typeInferenceSelfIndexingTypeParameter1.ts, 2, 35))
>T : Symbol(T, Decl(typeInferenceSelfIndexingTypeParameter1.ts, 2, 33))

property: string,
>property : Symbol(property, Decl(typeInferenceSelfIndexingTypeParameter1.ts, 2, 37))
property: K,
>property : Symbol(property, Decl(typeInferenceSelfIndexingTypeParameter1.ts, 2, 55))
>K : Symbol(K, Decl(typeInferenceSelfIndexingTypeParameter1.ts, 2, 35))

comparator: (a: T[keyof T], b: T[keyof T]) => 0 | 1 | -1,
>comparator : Symbol(comparator, Decl(typeInferenceSelfIndexingTypeParameter1.ts, 3, 19))
comparator: (a: T[K], b: T[K]) => 0 | 1 | -1,
>comparator : Symbol(comparator, Decl(typeInferenceSelfIndexingTypeParameter1.ts, 3, 14))
>a : Symbol(a, Decl(typeInferenceSelfIndexingTypeParameter1.ts, 4, 15))
>T : Symbol(T, Decl(typeInferenceSelfIndexingTypeParameter1.ts, 2, 33))
>K : Symbol(K, Decl(typeInferenceSelfIndexingTypeParameter1.ts, 2, 35))
>b : Symbol(b, Decl(typeInferenceSelfIndexingTypeParameter1.ts, 4, 23))
>T : Symbol(T, Decl(typeInferenceSelfIndexingTypeParameter1.ts, 2, 33))
>b : Symbol(b, Decl(typeInferenceSelfIndexingTypeParameter1.ts, 4, 29))
>T : Symbol(T, Decl(typeInferenceSelfIndexingTypeParameter1.ts, 2, 33))
>T : Symbol(T, Decl(typeInferenceSelfIndexingTypeParameter1.ts, 2, 33))
>K : Symbol(K, Decl(typeInferenceSelfIndexingTypeParameter1.ts, 2, 35))

) => Comparator<T>;
>Comparator : Symbol(Comparator, Decl(typeInferenceSelfIndexingTypeParameter1.ts, 0, 0))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,21 @@ type Comparator<T> = (a: T, b: T) => -1 | 0 | 1;
>1 : 1
> : ^

declare const createComparator: <T,>(
>createComparator : <T>(property: string, comparator: (a: T[keyof T], b: T[keyof T]) => 0 | 1 | -1) => Comparator<T>
> : ^ ^^ ^^ ^^ ^^ ^^^^^

property: string,
>property : string
> : ^^^^^^

comparator: (a: T[keyof T], b: T[keyof T]) => 0 | 1 | -1,
>comparator : (a: T[keyof T], b: T[keyof T]) => 0 | 1 | -1
> : ^ ^^ ^^ ^^ ^^^^^
>a : T[keyof T]
> : ^^^^^^^^^^
>b : T[keyof T]
> : ^^^^^^^^^^
declare const createComparator: <T, K extends keyof T>(
>createComparator : <T, K extends keyof T>(property: K, comparator: (a: T[K], b: T[K]) => 0 | 1 | -1) => Comparator<T>
> : ^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^

property: K,
>property : K
> : ^

comparator: (a: T[K], b: T[K]) => 0 | 1 | -1,
>comparator : (a: T[K], b: T[K]) => 0 | 1 | -1
> : ^ ^^ ^^ ^^ ^^^^^
>a : T[K]
> : ^^^^
>b : T[K]
> : ^^^^
>-1 : -1
> : ^^
>1 : 1
Expand Down Expand Up @@ -75,24 +75,24 @@ declare class ModuleGraphConnection {
}

const bySourceOrder = createComparator("sourceOrder", compareNumbers);
>bySourceOrder : Comparator<PartialInference<number, string | number | symbol>>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>createComparator("sourceOrder", compareNumbers) : Comparator<PartialInference<number, string | number | symbol>>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>createComparator : <T>(property: string, comparator: (a: T[keyof T], b: T[keyof T]) => 0 | 1 | -1) => Comparator<T>
> : ^ ^^ ^^ ^^ ^^ ^^^^^
>bySourceOrder : Comparator<Record<"sourceOrder", number>>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>createComparator("sourceOrder", compareNumbers) : Comparator<Record<"sourceOrder", number>>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>createComparator : <T, K extends keyof T>(property: K, comparator: (a: T[K], b: T[K]) => 0 | 1 | -1) => Comparator<T>
> : ^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^
>"sourceOrder" : "sourceOrder"
> : ^^^^^^^^^^^^^
>compareNumbers : (a: number, b: number) => 0 | 1 | -1
> : ^ ^^ ^^ ^^ ^^^^^

const byRangeStart = createComparator("rangeStart", compareNumbers);
>byRangeStart : Comparator<PartialInference<number, string | number | symbol>>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>createComparator("rangeStart", compareNumbers) : Comparator<PartialInference<number, string | number | symbol>>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>createComparator : <T>(property: string, comparator: (a: T[keyof T], b: T[keyof T]) => 0 | 1 | -1) => Comparator<T>
> : ^ ^^ ^^ ^^ ^^ ^^^^^
>byRangeStart : Comparator<Record<"rangeStart", number>>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>createComparator("rangeStart", compareNumbers) : Comparator<Record<"rangeStart", number>>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>createComparator : <T, K extends keyof T>(property: K, comparator: (a: T[K], b: T[K]) => 0 | 1 | -1) => Comparator<T>
> : ^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^
>"rangeStart" : "rangeStart"
> : ^^^^^^^^^^^^
>compareNumbers : (a: number, b: number) => 0 | 1 | -1
Expand Down Expand Up @@ -129,12 +129,12 @@ references.sort(concatComparators(bySourceOrder, byRangeStart));
> : ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^
>sort : (compareFn?: ((a: { connection: ModuleGraphConnection; sourceOrder: number; rangeStart: number | undefined; defer?: boolean; }, b: { connection: ModuleGraphConnection; sourceOrder: number; rangeStart: number | undefined; defer?: boolean; }) => number) | undefined) => { connection: ModuleGraphConnection; sourceOrder: number; rangeStart: number | undefined; defer?: boolean; }[]
> : ^ ^^^^^ ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^ ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^
>concatComparators(bySourceOrder, byRangeStart) : Comparator<PartialInference<number, string | number | symbol>>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>concatComparators(bySourceOrder, byRangeStart) : Comparator<Record<"sourceOrder", number>>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>concatComparators : <T>(c1: Comparator<T>, c2: Comparator<T>, ...cRest: Comparator<T>[]) => Comparator<T>
> : ^ ^^ ^^ ^^ ^^ ^^^^^ ^^ ^^^^^
>bySourceOrder : Comparator<PartialInference<number, string | number | symbol>>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>byRangeStart : Comparator<PartialInference<number, string | number | symbol>>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>bySourceOrder : Comparator<Record<"sourceOrder", number>>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>byRangeStart : Comparator<Record<"rangeStart", number>>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Loading