mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-06-10 18:04:18 -05:00
Reverse mapped types should have inferable indexes if their source had an inferable index (#33450)
This commit is contained in:
@@ -15004,9 +15004,9 @@ namespace ts {
|
||||
* Return true if type was inferred from an object literal, written as an object type literal, or is the shape of a module
|
||||
* with no call or construct signatures.
|
||||
*/
|
||||
function isObjectTypeWithInferableIndex(type: Type) {
|
||||
return type.symbol && (type.symbol.flags & (SymbolFlags.ObjectLiteral | SymbolFlags.TypeLiteral | SymbolFlags.Enum | SymbolFlags.ValueModule)) !== 0 &&
|
||||
!typeHasCallOrConstructSignatures(type);
|
||||
function isObjectTypeWithInferableIndex(type: Type): boolean {
|
||||
return !!(type.symbol && (type.symbol.flags & (SymbolFlags.ObjectLiteral | SymbolFlags.TypeLiteral | SymbolFlags.Enum | SymbolFlags.ValueModule)) !== 0 &&
|
||||
!typeHasCallOrConstructSignatures(type)) || !!(getObjectFlags(type) & ObjectFlags.ReverseMapped && isObjectTypeWithInferableIndex((type as ReverseMappedType).source));
|
||||
}
|
||||
|
||||
function createSymbolWithType(source: Symbol, type: Type | undefined) {
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
//// [reverseMappedTypeAssignableToIndex.ts]
|
||||
// Simple mapped type and inferrence
|
||||
type Mapped<T> = { [K in keyof T]: { name: T[K] } };
|
||||
type InferFromMapped<T> = T extends Mapped<infer R> ? R : never;
|
||||
|
||||
// Object literal type and associated mapped type
|
||||
// Note that in the real code we don't have a direct reference to LiteralType
|
||||
type LiteralType = {
|
||||
first: "first";
|
||||
second: "second";
|
||||
}
|
||||
type MappedLiteralType = {
|
||||
first: { name: "first" },
|
||||
second: { name: "second" },
|
||||
};
|
||||
|
||||
type Inferred = InferFromMapped<MappedLiteralType>;
|
||||
|
||||
// UNEXPECTED resolves to false
|
||||
type Test1 = Inferred extends Record<any, string> ? true : false;
|
||||
|
||||
//// [reverseMappedTypeAssignableToIndex.js]
|
||||
@@ -0,0 +1,54 @@
|
||||
=== tests/cases/compiler/reverseMappedTypeAssignableToIndex.ts ===
|
||||
// Simple mapped type and inferrence
|
||||
type Mapped<T> = { [K in keyof T]: { name: T[K] } };
|
||||
>Mapped : Symbol(Mapped, Decl(reverseMappedTypeAssignableToIndex.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(reverseMappedTypeAssignableToIndex.ts, 1, 12))
|
||||
>K : Symbol(K, Decl(reverseMappedTypeAssignableToIndex.ts, 1, 20))
|
||||
>T : Symbol(T, Decl(reverseMappedTypeAssignableToIndex.ts, 1, 12))
|
||||
>name : Symbol(name, Decl(reverseMappedTypeAssignableToIndex.ts, 1, 36))
|
||||
>T : Symbol(T, Decl(reverseMappedTypeAssignableToIndex.ts, 1, 12))
|
||||
>K : Symbol(K, Decl(reverseMappedTypeAssignableToIndex.ts, 1, 20))
|
||||
|
||||
type InferFromMapped<T> = T extends Mapped<infer R> ? R : never;
|
||||
>InferFromMapped : Symbol(InferFromMapped, Decl(reverseMappedTypeAssignableToIndex.ts, 1, 52))
|
||||
>T : Symbol(T, Decl(reverseMappedTypeAssignableToIndex.ts, 2, 21))
|
||||
>T : Symbol(T, Decl(reverseMappedTypeAssignableToIndex.ts, 2, 21))
|
||||
>Mapped : Symbol(Mapped, Decl(reverseMappedTypeAssignableToIndex.ts, 0, 0))
|
||||
>R : Symbol(R, Decl(reverseMappedTypeAssignableToIndex.ts, 2, 48))
|
||||
>R : Symbol(R, Decl(reverseMappedTypeAssignableToIndex.ts, 2, 48))
|
||||
|
||||
// Object literal type and associated mapped type
|
||||
// Note that in the real code we don't have a direct reference to LiteralType
|
||||
type LiteralType = {
|
||||
>LiteralType : Symbol(LiteralType, Decl(reverseMappedTypeAssignableToIndex.ts, 2, 64))
|
||||
|
||||
first: "first";
|
||||
>first : Symbol(first, Decl(reverseMappedTypeAssignableToIndex.ts, 6, 20))
|
||||
|
||||
second: "second";
|
||||
>second : Symbol(second, Decl(reverseMappedTypeAssignableToIndex.ts, 7, 16))
|
||||
}
|
||||
type MappedLiteralType = {
|
||||
>MappedLiteralType : Symbol(MappedLiteralType, Decl(reverseMappedTypeAssignableToIndex.ts, 9, 1))
|
||||
|
||||
first: { name: "first" },
|
||||
>first : Symbol(first, Decl(reverseMappedTypeAssignableToIndex.ts, 10, 26))
|
||||
>name : Symbol(name, Decl(reverseMappedTypeAssignableToIndex.ts, 11, 9))
|
||||
|
||||
second: { name: "second" },
|
||||
>second : Symbol(second, Decl(reverseMappedTypeAssignableToIndex.ts, 11, 26))
|
||||
>name : Symbol(name, Decl(reverseMappedTypeAssignableToIndex.ts, 12, 10))
|
||||
|
||||
};
|
||||
|
||||
type Inferred = InferFromMapped<MappedLiteralType>;
|
||||
>Inferred : Symbol(Inferred, Decl(reverseMappedTypeAssignableToIndex.ts, 13, 2))
|
||||
>InferFromMapped : Symbol(InferFromMapped, Decl(reverseMappedTypeAssignableToIndex.ts, 1, 52))
|
||||
>MappedLiteralType : Symbol(MappedLiteralType, Decl(reverseMappedTypeAssignableToIndex.ts, 9, 1))
|
||||
|
||||
// UNEXPECTED resolves to false
|
||||
type Test1 = Inferred extends Record<any, string> ? true : false;
|
||||
>Test1 : Symbol(Test1, Decl(reverseMappedTypeAssignableToIndex.ts, 15, 51))
|
||||
>Inferred : Symbol(Inferred, Decl(reverseMappedTypeAssignableToIndex.ts, 13, 2))
|
||||
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
=== tests/cases/compiler/reverseMappedTypeAssignableToIndex.ts ===
|
||||
// Simple mapped type and inferrence
|
||||
type Mapped<T> = { [K in keyof T]: { name: T[K] } };
|
||||
>Mapped : Mapped<T>
|
||||
>name : T[K]
|
||||
|
||||
type InferFromMapped<T> = T extends Mapped<infer R> ? R : never;
|
||||
>InferFromMapped : InferFromMapped<T>
|
||||
|
||||
// Object literal type and associated mapped type
|
||||
// Note that in the real code we don't have a direct reference to LiteralType
|
||||
type LiteralType = {
|
||||
>LiteralType : LiteralType
|
||||
|
||||
first: "first";
|
||||
>first : "first"
|
||||
|
||||
second: "second";
|
||||
>second : "second"
|
||||
}
|
||||
type MappedLiteralType = {
|
||||
>MappedLiteralType : MappedLiteralType
|
||||
|
||||
first: { name: "first" },
|
||||
>first : { name: "first"; }
|
||||
>name : "first"
|
||||
|
||||
second: { name: "second" },
|
||||
>second : { name: "second"; }
|
||||
>name : "second"
|
||||
|
||||
};
|
||||
|
||||
type Inferred = InferFromMapped<MappedLiteralType>;
|
||||
>Inferred : { first: "first"; second: "second"; }
|
||||
|
||||
// UNEXPECTED resolves to false
|
||||
type Test1 = Inferred extends Record<any, string> ? true : false;
|
||||
>Test1 : true
|
||||
>true : true
|
||||
>false : false
|
||||
|
||||
19
tests/cases/compiler/reverseMappedTypeAssignableToIndex.ts
Normal file
19
tests/cases/compiler/reverseMappedTypeAssignableToIndex.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
// Simple mapped type and inferrence
|
||||
type Mapped<T> = { [K in keyof T]: { name: T[K] } };
|
||||
type InferFromMapped<T> = T extends Mapped<infer R> ? R : never;
|
||||
|
||||
// Object literal type and associated mapped type
|
||||
// Note that in the real code we don't have a direct reference to LiteralType
|
||||
type LiteralType = {
|
||||
first: "first";
|
||||
second: "second";
|
||||
}
|
||||
type MappedLiteralType = {
|
||||
first: { name: "first" },
|
||||
second: { name: "second" },
|
||||
};
|
||||
|
||||
type Inferred = InferFromMapped<MappedLiteralType>;
|
||||
|
||||
// UNEXPECTED resolves to false
|
||||
type Test1 = Inferred extends Record<any, string> ? true : false;
|
||||
Reference in New Issue
Block a user