Widen reverse mapped type properties to fix them being treated as EPC-valid sources (#62722)

This commit is contained in:
Mateusz Burzyński 2025-12-05 19:45:33 +01:00 committed by GitHub
parent b33d37201e
commit 0752278137
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 610 additions and 1 deletions

View File

@ -26438,7 +26438,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
const templateType = getTemplateTypeFromMappedType(target);
const inference = createInferenceInfo(typeParameter);
inferTypes([inference], sourceType, templateType);
return getTypeFromInference(inference) || unknownType;
return getWidenedType(getTypeFromInference(inference) || unknownType);
}
function inferReverseMappedType(source: Type, target: MappedType, constraint: IndexType): Type | undefined {

View File

@ -0,0 +1,181 @@
//// [tests/cases/compiler/reverseMappedTypeInferenceWidening1.ts] ////
=== reverseMappedTypeInferenceWidening1.ts ===
// https://github.com/microsoft/TypeScript/issues/62720
type TypeFunction<ReturnType = unknown> = (...args: any[]) => ReturnType;
>TypeFunction : Symbol(TypeFunction, Decl(reverseMappedTypeInferenceWidening1.ts, 0, 0))
>ReturnType : Symbol(ReturnType, Decl(reverseMappedTypeInferenceWidening1.ts, 2, 18))
>args : Symbol(args, Decl(reverseMappedTypeInferenceWidening1.ts, 2, 43))
>ReturnType : Symbol(ReturnType, Decl(reverseMappedTypeInferenceWidening1.ts, 2, 18))
type Flags = {
>Flags : Symbol(Flags, Decl(reverseMappedTypeInferenceWidening1.ts, 2, 73))
[flagName: string]: {
>flagName : Symbol(flagName, Decl(reverseMappedTypeInferenceWidening1.ts, 4, 3))
type: TypeFunction;
>type : Symbol(type, Decl(reverseMappedTypeInferenceWidening1.ts, 4, 23))
>TypeFunction : Symbol(TypeFunction, Decl(reverseMappedTypeInferenceWidening1.ts, 0, 0))
default?: unknown;
>default : Symbol(default, Decl(reverseMappedTypeInferenceWidening1.ts, 5, 23))
};
};
type TypeFlag<Schemas extends Flags> = {
>TypeFlag : Symbol(TypeFlag, Decl(reverseMappedTypeInferenceWidening1.ts, 8, 2))
>Schemas : Symbol(Schemas, Decl(reverseMappedTypeInferenceWidening1.ts, 9, 14))
>Flags : Symbol(Flags, Decl(reverseMappedTypeInferenceWidening1.ts, 2, 73))
[flag in keyof Schemas]: Schemas[flag] extends { type: TypeFunction<infer T> }
>flag : Symbol(flag, Decl(reverseMappedTypeInferenceWidening1.ts, 10, 3))
>Schemas : Symbol(Schemas, Decl(reverseMappedTypeInferenceWidening1.ts, 9, 14))
>Schemas : Symbol(Schemas, Decl(reverseMappedTypeInferenceWidening1.ts, 9, 14))
>flag : Symbol(flag, Decl(reverseMappedTypeInferenceWidening1.ts, 10, 3))
>type : Symbol(type, Decl(reverseMappedTypeInferenceWidening1.ts, 10, 50))
>TypeFunction : Symbol(TypeFunction, Decl(reverseMappedTypeInferenceWidening1.ts, 0, 0))
>T : Symbol(T, Decl(reverseMappedTypeInferenceWidening1.ts, 10, 75))
? T
>T : Symbol(T, Decl(reverseMappedTypeInferenceWidening1.ts, 10, 75))
: never;
};
declare function fn1<Options extends Flags>(
>fn1 : Symbol(fn1, Decl(reverseMappedTypeInferenceWidening1.ts, 13, 2))
>Options : Symbol(Options, Decl(reverseMappedTypeInferenceWidening1.ts, 15, 21))
>Flags : Symbol(Flags, Decl(reverseMappedTypeInferenceWidening1.ts, 2, 73))
options: Options,
>options : Symbol(options, Decl(reverseMappedTypeInferenceWidening1.ts, 15, 44))
>Options : Symbol(Options, Decl(reverseMappedTypeInferenceWidening1.ts, 15, 21))
): TypeFlag<Options>;
>TypeFlag : Symbol(TypeFlag, Decl(reverseMappedTypeInferenceWidening1.ts, 8, 2))
>Options : Symbol(Options, Decl(reverseMappedTypeInferenceWidening1.ts, 15, 21))
const result1 = fn1({
>result1 : Symbol(result1, Decl(reverseMappedTypeInferenceWidening1.ts, 19, 5))
>fn1 : Symbol(fn1, Decl(reverseMappedTypeInferenceWidening1.ts, 13, 2))
booleanFlag: { type: Boolean },
>booleanFlag : Symbol(booleanFlag, Decl(reverseMappedTypeInferenceWidening1.ts, 19, 21))
>type : Symbol(type, Decl(reverseMappedTypeInferenceWidening1.ts, 20, 16))
>Boolean : Symbol(Boolean, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
booleanFlagDefault: {
>booleanFlagDefault : Symbol(booleanFlagDefault, Decl(reverseMappedTypeInferenceWidening1.ts, 20, 33))
type: Boolean,
>type : Symbol(type, Decl(reverseMappedTypeInferenceWidening1.ts, 21, 23))
>Boolean : Symbol(Boolean, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
default: false,
>default : Symbol(default, Decl(reverseMappedTypeInferenceWidening1.ts, 22, 18))
},
});
result1.booleanFlag; // boolean
>result1.booleanFlag : Symbol(booleanFlag, Decl(reverseMappedTypeInferenceWidening1.ts, 19, 21))
>result1 : Symbol(result1, Decl(reverseMappedTypeInferenceWidening1.ts, 19, 5))
>booleanFlag : Symbol(booleanFlag, Decl(reverseMappedTypeInferenceWidening1.ts, 19, 21))
result1.booleanFlagDefault; // boolean
>result1.booleanFlagDefault : Symbol(booleanFlagDefault, Decl(reverseMappedTypeInferenceWidening1.ts, 20, 33))
>result1 : Symbol(result1, Decl(reverseMappedTypeInferenceWidening1.ts, 19, 5))
>booleanFlagDefault : Symbol(booleanFlagDefault, Decl(reverseMappedTypeInferenceWidening1.ts, 20, 33))
declare function fn2<Options extends Flags>(
>fn2 : Symbol(fn2, Decl(reverseMappedTypeInferenceWidening1.ts, 27, 27))
>Options : Symbol(Options, Decl(reverseMappedTypeInferenceWidening1.ts, 29, 21))
>Flags : Symbol(Flags, Decl(reverseMappedTypeInferenceWidening1.ts, 2, 73))
options: Readonly<Options>,
>options : Symbol(options, Decl(reverseMappedTypeInferenceWidening1.ts, 29, 44))
>Readonly : Symbol(Readonly, Decl(lib.es5.d.ts, --, --))
>Options : Symbol(Options, Decl(reverseMappedTypeInferenceWidening1.ts, 29, 21))
): TypeFlag<Options>;
>TypeFlag : Symbol(TypeFlag, Decl(reverseMappedTypeInferenceWidening1.ts, 8, 2))
>Options : Symbol(Options, Decl(reverseMappedTypeInferenceWidening1.ts, 29, 21))
const result2 = fn2({
>result2 : Symbol(result2, Decl(reverseMappedTypeInferenceWidening1.ts, 33, 5))
>fn2 : Symbol(fn2, Decl(reverseMappedTypeInferenceWidening1.ts, 27, 27))
booleanFlag: { type: Boolean },
>booleanFlag : Symbol(booleanFlag, Decl(reverseMappedTypeInferenceWidening1.ts, 33, 21))
>type : Symbol(type, Decl(reverseMappedTypeInferenceWidening1.ts, 34, 16))
>Boolean : Symbol(Boolean, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
booleanFlagDefault: {
>booleanFlagDefault : Symbol(booleanFlagDefault, Decl(reverseMappedTypeInferenceWidening1.ts, 34, 33))
type: Boolean,
>type : Symbol(type, Decl(reverseMappedTypeInferenceWidening1.ts, 35, 23))
>Boolean : Symbol(Boolean, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
default: false,
>default : Symbol(default, Decl(reverseMappedTypeInferenceWidening1.ts, 36, 18))
},
});
result2.booleanFlag; // boolean
>result2.booleanFlag : Symbol(booleanFlag, Decl(reverseMappedTypeInferenceWidening1.ts, 33, 21))
>result2 : Symbol(result2, Decl(reverseMappedTypeInferenceWidening1.ts, 33, 5))
>booleanFlag : Symbol(booleanFlag, Decl(reverseMappedTypeInferenceWidening1.ts, 33, 21))
result2.booleanFlagDefault; // boolean
>result2.booleanFlagDefault : Symbol(booleanFlagDefault, Decl(reverseMappedTypeInferenceWidening1.ts, 34, 33))
>result2 : Symbol(result2, Decl(reverseMappedTypeInferenceWidening1.ts, 33, 5))
>booleanFlagDefault : Symbol(booleanFlagDefault, Decl(reverseMappedTypeInferenceWidening1.ts, 34, 33))
declare function fn3<Options extends Flags>(
>fn3 : Symbol(fn3, Decl(reverseMappedTypeInferenceWidening1.ts, 41, 27))
>Options : Symbol(Options, Decl(reverseMappedTypeInferenceWidening1.ts, 43, 21))
>Flags : Symbol(Flags, Decl(reverseMappedTypeInferenceWidening1.ts, 2, 73))
options: Readonly<Options>,
>options : Symbol(options, Decl(reverseMappedTypeInferenceWidening1.ts, 43, 44))
>Readonly : Symbol(Readonly, Decl(lib.es5.d.ts, --, --))
>Options : Symbol(Options, Decl(reverseMappedTypeInferenceWidening1.ts, 43, 21))
): Options;
>Options : Symbol(Options, Decl(reverseMappedTypeInferenceWidening1.ts, 43, 21))
const result3 = fn3({
>result3 : Symbol(result3, Decl(reverseMappedTypeInferenceWidening1.ts, 47, 5))
>fn3 : Symbol(fn3, Decl(reverseMappedTypeInferenceWidening1.ts, 41, 27))
booleanFlag: { type: Boolean },
>booleanFlag : Symbol(booleanFlag, Decl(reverseMappedTypeInferenceWidening1.ts, 47, 21))
>type : Symbol(type, Decl(reverseMappedTypeInferenceWidening1.ts, 48, 16))
>Boolean : Symbol(Boolean, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
booleanFlagDefault: {
>booleanFlagDefault : Symbol(booleanFlagDefault, Decl(reverseMappedTypeInferenceWidening1.ts, 48, 33))
type: Boolean,
>type : Symbol(type, Decl(reverseMappedTypeInferenceWidening1.ts, 49, 23))
>Boolean : Symbol(Boolean, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
default: false, // no cursed EPC failure here
>default : Symbol(default, Decl(reverseMappedTypeInferenceWidening1.ts, 50, 18))
},
});
declare function takeType(arg: { type: unknown }): void;
>takeType : Symbol(takeType, Decl(reverseMappedTypeInferenceWidening1.ts, 53, 3))
>arg : Symbol(arg, Decl(reverseMappedTypeInferenceWidening1.ts, 55, 26))
>type : Symbol(type, Decl(reverseMappedTypeInferenceWidening1.ts, 55, 32))
takeType(result3.booleanFlagDefault);
>takeType : Symbol(takeType, Decl(reverseMappedTypeInferenceWidening1.ts, 53, 3))
>result3.booleanFlagDefault : Symbol(booleanFlagDefault, Decl(reverseMappedTypeInferenceWidening1.ts, 48, 33))
>result3 : Symbol(result3, Decl(reverseMappedTypeInferenceWidening1.ts, 47, 5))
>booleanFlagDefault : Symbol(booleanFlagDefault, Decl(reverseMappedTypeInferenceWidening1.ts, 48, 33))

View File

@ -0,0 +1,244 @@
//// [tests/cases/compiler/reverseMappedTypeInferenceWidening1.ts] ////
=== reverseMappedTypeInferenceWidening1.ts ===
// https://github.com/microsoft/TypeScript/issues/62720
type TypeFunction<ReturnType = unknown> = (...args: any[]) => ReturnType;
>TypeFunction : TypeFunction<ReturnType>
> : ^^^^^^^^^^^^^^^^^^^^^^^^
>args : any[]
> : ^^^^^
type Flags = {
>Flags : Flags
> : ^^^^^
[flagName: string]: {
>flagName : string
> : ^^^^^^
type: TypeFunction;
>type : TypeFunction<unknown>
> : ^^^^^^^^^^^^^^^^^^^^^
default?: unknown;
>default : unknown
> : ^^^^^^^
};
};
type TypeFlag<Schemas extends Flags> = {
>TypeFlag : TypeFlag<Schemas>
> : ^^^^^^^^^^^^^^^^^
[flag in keyof Schemas]: Schemas[flag] extends { type: TypeFunction<infer T> }
>type : TypeFunction<T>
> : ^^^^^^^^^^^^^^^
? T
: never;
};
declare function fn1<Options extends Flags>(
>fn1 : <Options extends Flags>(options: Options) => TypeFlag<Options>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
options: Options,
>options : Options
> : ^^^^^^^
): TypeFlag<Options>;
const result1 = fn1({
>result1 : TypeFlag<{ booleanFlag: { type: BooleanConstructor; }; booleanFlagDefault: { type: BooleanConstructor; default: boolean; }; }>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>fn1({ booleanFlag: { type: Boolean }, booleanFlagDefault: { type: Boolean, default: false, },}) : TypeFlag<{ booleanFlag: { type: BooleanConstructor; }; booleanFlagDefault: { type: BooleanConstructor; default: boolean; }; }>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>fn1 : <Options extends Flags>(options: Options) => TypeFlag<Options>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>{ booleanFlag: { type: Boolean }, booleanFlagDefault: { type: Boolean, default: false, },} : { booleanFlag: { type: BooleanConstructor; }; booleanFlagDefault: { type: BooleanConstructor; default: false; }; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
booleanFlag: { type: Boolean },
>booleanFlag : { type: BooleanConstructor; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>{ type: Boolean } : { type: BooleanConstructor; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>type : BooleanConstructor
> : ^^^^^^^^^^^^^^^^^^
>Boolean : BooleanConstructor
> : ^^^^^^^^^^^^^^^^^^
booleanFlagDefault: {
>booleanFlagDefault : { type: BooleanConstructor; default: false; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>{ type: Boolean, default: false, } : { type: BooleanConstructor; default: false; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
type: Boolean,
>type : BooleanConstructor
> : ^^^^^^^^^^^^^^^^^^
>Boolean : BooleanConstructor
> : ^^^^^^^^^^^^^^^^^^
default: false,
>default : false
> : ^^^^^
>false : false
> : ^^^^^
},
});
result1.booleanFlag; // boolean
>result1.booleanFlag : boolean
> : ^^^^^^^
>result1 : TypeFlag<{ booleanFlag: { type: BooleanConstructor; }; booleanFlagDefault: { type: BooleanConstructor; default: boolean; }; }>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>booleanFlag : boolean
> : ^^^^^^^
result1.booleanFlagDefault; // boolean
>result1.booleanFlagDefault : boolean
> : ^^^^^^^
>result1 : TypeFlag<{ booleanFlag: { type: BooleanConstructor; }; booleanFlagDefault: { type: BooleanConstructor; default: boolean; }; }>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>booleanFlagDefault : boolean
> : ^^^^^^^
declare function fn2<Options extends Flags>(
>fn2 : <Options extends Flags>(options: Readonly<Options>) => TypeFlag<Options>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
options: Readonly<Options>,
>options : Readonly<Options>
> : ^^^^^^^^^^^^^^^^^
): TypeFlag<Options>;
const result2 = fn2({
>result2 : TypeFlag<{ booleanFlag: { type: BooleanConstructor; }; booleanFlagDefault: { type: BooleanConstructor; default: boolean; }; }>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>fn2({ booleanFlag: { type: Boolean }, booleanFlagDefault: { type: Boolean, default: false, },}) : TypeFlag<{ booleanFlag: { type: BooleanConstructor; }; booleanFlagDefault: { type: BooleanConstructor; default: boolean; }; }>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>fn2 : <Options extends Flags>(options: Readonly<Options>) => TypeFlag<Options>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>{ booleanFlag: { type: Boolean }, booleanFlagDefault: { type: Boolean, default: false, },} : { booleanFlag: { type: BooleanConstructor; }; booleanFlagDefault: { type: BooleanConstructor; default: false; }; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
booleanFlag: { type: Boolean },
>booleanFlag : { type: BooleanConstructor; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>{ type: Boolean } : { type: BooleanConstructor; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>type : BooleanConstructor
> : ^^^^^^^^^^^^^^^^^^
>Boolean : BooleanConstructor
> : ^^^^^^^^^^^^^^^^^^
booleanFlagDefault: {
>booleanFlagDefault : { type: BooleanConstructor; default: false; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>{ type: Boolean, default: false, } : { type: BooleanConstructor; default: false; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
type: Boolean,
>type : BooleanConstructor
> : ^^^^^^^^^^^^^^^^^^
>Boolean : BooleanConstructor
> : ^^^^^^^^^^^^^^^^^^
default: false,
>default : false
> : ^^^^^
>false : false
> : ^^^^^
},
});
result2.booleanFlag; // boolean
>result2.booleanFlag : boolean
> : ^^^^^^^
>result2 : TypeFlag<{ booleanFlag: { type: BooleanConstructor; }; booleanFlagDefault: { type: BooleanConstructor; default: boolean; }; }>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>booleanFlag : boolean
> : ^^^^^^^
result2.booleanFlagDefault; // boolean
>result2.booleanFlagDefault : boolean
> : ^^^^^^^
>result2 : TypeFlag<{ booleanFlag: { type: BooleanConstructor; }; booleanFlagDefault: { type: BooleanConstructor; default: boolean; }; }>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>booleanFlagDefault : boolean
> : ^^^^^^^
declare function fn3<Options extends Flags>(
>fn3 : <Options extends Flags>(options: Readonly<Options>) => Options
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
options: Readonly<Options>,
>options : Readonly<Options>
> : ^^^^^^^^^^^^^^^^^
): Options;
const result3 = fn3({
>result3 : { booleanFlag: { type: BooleanConstructor; }; booleanFlagDefault: { type: BooleanConstructor; default: boolean; }; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>fn3({ booleanFlag: { type: Boolean }, booleanFlagDefault: { type: Boolean, default: false, // no cursed EPC failure here },}) : { booleanFlag: { type: BooleanConstructor; }; booleanFlagDefault: { type: BooleanConstructor; default: boolean; }; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>fn3 : <Options extends Flags>(options: Readonly<Options>) => Options
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>{ booleanFlag: { type: Boolean }, booleanFlagDefault: { type: Boolean, default: false, // no cursed EPC failure here },} : { booleanFlag: { type: BooleanConstructor; }; booleanFlagDefault: { type: BooleanConstructor; default: false; }; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
booleanFlag: { type: Boolean },
>booleanFlag : { type: BooleanConstructor; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>{ type: Boolean } : { type: BooleanConstructor; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>type : BooleanConstructor
> : ^^^^^^^^^^^^^^^^^^
>Boolean : BooleanConstructor
> : ^^^^^^^^^^^^^^^^^^
booleanFlagDefault: {
>booleanFlagDefault : { type: BooleanConstructor; default: false; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>{ type: Boolean, default: false, // no cursed EPC failure here } : { type: BooleanConstructor; default: false; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
type: Boolean,
>type : BooleanConstructor
> : ^^^^^^^^^^^^^^^^^^
>Boolean : BooleanConstructor
> : ^^^^^^^^^^^^^^^^^^
default: false, // no cursed EPC failure here
>default : false
> : ^^^^^
>false : false
> : ^^^^^
},
});
declare function takeType(arg: { type: unknown }): void;
>takeType : (arg: { type: unknown; }) => void
> : ^ ^^ ^^^^^
>arg : { type: unknown; }
> : ^^^^^^^^ ^^^
>type : unknown
> : ^^^^^^^
takeType(result3.booleanFlagDefault);
>takeType(result3.booleanFlagDefault) : void
> : ^^^^
>takeType : (arg: { type: unknown; }) => void
> : ^ ^^ ^^^^^
>result3.booleanFlagDefault : { type: BooleanConstructor; default: boolean; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>result3 : { booleanFlag: { type: BooleanConstructor; }; booleanFlagDefault: { type: BooleanConstructor; default: boolean; }; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>booleanFlagDefault : { type: BooleanConstructor; default: boolean; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -0,0 +1,45 @@
//// [tests/cases/compiler/reverseMappedTypeInferenceWidening2.ts] ////
=== reverseMappedTypeInferenceWidening2.ts ===
declare function test1<T extends Record<string, { prop: unknown }>>(arg: {
>test1 : Symbol(test1, Decl(reverseMappedTypeInferenceWidening2.ts, 0, 0))
>T : Symbol(T, Decl(reverseMappedTypeInferenceWidening2.ts, 0, 23))
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
>prop : Symbol(prop, Decl(reverseMappedTypeInferenceWidening2.ts, 0, 49))
>arg : Symbol(arg, Decl(reverseMappedTypeInferenceWidening2.ts, 0, 68))
[K in keyof T]: T[K];
>K : Symbol(K, Decl(reverseMappedTypeInferenceWidening2.ts, 1, 3))
>T : Symbol(T, Decl(reverseMappedTypeInferenceWidening2.ts, 0, 23))
>T : Symbol(T, Decl(reverseMappedTypeInferenceWidening2.ts, 0, 23))
>K : Symbol(K, Decl(reverseMappedTypeInferenceWidening2.ts, 1, 3))
}): T;
>T : Symbol(T, Decl(reverseMappedTypeInferenceWidening2.ts, 0, 23))
const res1 = test1({
>res1 : Symbol(res1, Decl(reverseMappedTypeInferenceWidening2.ts, 4, 5))
>test1 : Symbol(test1, Decl(reverseMappedTypeInferenceWidening2.ts, 0, 0))
foo: {
>foo : Symbol(foo, Decl(reverseMappedTypeInferenceWidening2.ts, 4, 20))
prop: 1,
>prop : Symbol(prop, Decl(reverseMappedTypeInferenceWidening2.ts, 5, 8))
prop2: "",
>prop2 : Symbol(prop2, Decl(reverseMappedTypeInferenceWidening2.ts, 6, 12))
},
bar: {
>bar : Symbol(bar, Decl(reverseMappedTypeInferenceWidening2.ts, 8, 4))
prop: true,
>prop : Symbol(prop, Decl(reverseMappedTypeInferenceWidening2.ts, 9, 8))
prop2: null,
>prop2 : Symbol(prop2, Decl(reverseMappedTypeInferenceWidening2.ts, 10, 15))
},
});

View File

@ -0,0 +1,62 @@
//// [tests/cases/compiler/reverseMappedTypeInferenceWidening2.ts] ////
=== reverseMappedTypeInferenceWidening2.ts ===
declare function test1<T extends Record<string, { prop: unknown }>>(arg: {
>test1 : <T extends Record<string, { prop: unknown; }>>(arg: { [K in keyof T]: T[K]; }) => T
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>prop : unknown
> : ^^^^^^^
>arg : { [K in keyof T]: T[K]; }
> : ^^^ ^^^^^^^^^^^^^^^^^^^^^
[K in keyof T]: T[K];
}): T;
const res1 = test1({
>res1 : { foo: { prop: number; prop2: string; }; bar: { prop: boolean; prop2: null; }; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>test1({ foo: { prop: 1, prop2: "", }, bar: { prop: true, prop2: null, },}) : { foo: { prop: number; prop2: string; }; bar: { prop: boolean; prop2: null; }; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>test1 : <T extends Record<string, { prop: unknown; }>>(arg: { [K in keyof T]: T[K]; }) => T
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
>{ foo: { prop: 1, prop2: "", }, bar: { prop: true, prop2: null, },} : { foo: { prop: number; prop2: string; }; bar: { prop: true; prop2: null; }; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
foo: {
>foo : { prop: number; prop2: string; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>{ prop: 1, prop2: "", } : { prop: number; prop2: string; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
prop: 1,
>prop : number
> : ^^^^^^
>1 : 1
> : ^
prop2: "",
>prop2 : string
> : ^^^^^^
>"" : ""
> : ^^
},
bar: {
>bar : { prop: true; prop2: null; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>{ prop: true, prop2: null, } : { prop: true; prop2: null; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
prop: true,
>prop : true
> : ^^^^
>true : true
> : ^^^^
prop2: null,
>prop2 : null
> : ^^^^
},
});

View File

@ -0,0 +1,60 @@
// @strict: true
// @noEmit: true
// https://github.com/microsoft/TypeScript/issues/62720
type TypeFunction<ReturnType = unknown> = (...args: any[]) => ReturnType;
type Flags = {
[flagName: string]: {
type: TypeFunction;
default?: unknown;
};
};
type TypeFlag<Schemas extends Flags> = {
[flag in keyof Schemas]: Schemas[flag] extends { type: TypeFunction<infer T> }
? T
: never;
};
declare function fn1<Options extends Flags>(
options: Options,
): TypeFlag<Options>;
const result1 = fn1({
booleanFlag: { type: Boolean },
booleanFlagDefault: {
type: Boolean,
default: false,
},
});
result1.booleanFlag; // boolean
result1.booleanFlagDefault; // boolean
declare function fn2<Options extends Flags>(
options: Readonly<Options>,
): TypeFlag<Options>;
const result2 = fn2({
booleanFlag: { type: Boolean },
booleanFlagDefault: {
type: Boolean,
default: false,
},
});
result2.booleanFlag; // boolean
result2.booleanFlagDefault; // boolean
declare function fn3<Options extends Flags>(
options: Readonly<Options>,
): Options;
const result3 = fn3({
booleanFlag: { type: Boolean },
booleanFlagDefault: {
type: Boolean,
default: false, // no cursed EPC failure here
},
});
declare function takeType(arg: { type: unknown }): void;
takeType(result3.booleanFlagDefault);

View File

@ -0,0 +1,17 @@
// @strict: true
// @noEmit: true
declare function test1<T extends Record<string, { prop: unknown }>>(arg: {
[K in keyof T]: T[K];
}): T;
const res1 = test1({
foo: {
prop: 1,
prop2: "",
},
bar: {
prop: true,
prop2: null,
},
});