mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 12:32:08 -06:00
Fixed an issue with reverse mapped types inference when single type variable is left after inferring from matching types (#55941)
Co-authored-by: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com>
This commit is contained in:
parent
30f3ce7b51
commit
6edfef8c0d
@ -25354,7 +25354,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
target = getIntersectionType(targets);
|
||||
}
|
||||
}
|
||||
else if (target.flags & (TypeFlags.IndexedAccess | TypeFlags.Substitution)) {
|
||||
if (target.flags & (TypeFlags.IndexedAccess | TypeFlags.Substitution)) {
|
||||
target = getActualTypeVariable(target);
|
||||
}
|
||||
if (target.flags & TypeFlags.TypeVariable) {
|
||||
|
||||
172
tests/baselines/reference/reverseMappedUnionInference.symbols
Normal file
172
tests/baselines/reference/reverseMappedUnionInference.symbols
Normal file
@ -0,0 +1,172 @@
|
||||
//// [tests/cases/compiler/reverseMappedUnionInference.ts] ////
|
||||
|
||||
=== reverseMappedUnionInference.ts ===
|
||||
interface AnyExtractor<Result> {
|
||||
>AnyExtractor : Symbol(AnyExtractor, Decl(reverseMappedUnionInference.ts, 0, 0))
|
||||
>Result : Symbol(Result, Decl(reverseMappedUnionInference.ts, 0, 23))
|
||||
|
||||
matches: (node: any) => boolean;
|
||||
>matches : Symbol(AnyExtractor.matches, Decl(reverseMappedUnionInference.ts, 0, 32))
|
||||
>node : Symbol(node, Decl(reverseMappedUnionInference.ts, 1, 12))
|
||||
|
||||
extract: (node: any) => Result | undefined;
|
||||
>extract : Symbol(AnyExtractor.extract, Decl(reverseMappedUnionInference.ts, 1, 34))
|
||||
>node : Symbol(node, Decl(reverseMappedUnionInference.ts, 2, 12))
|
||||
>Result : Symbol(Result, Decl(reverseMappedUnionInference.ts, 0, 23))
|
||||
}
|
||||
|
||||
interface Extractor<T, Result> {
|
||||
>Extractor : Symbol(Extractor, Decl(reverseMappedUnionInference.ts, 3, 1))
|
||||
>T : Symbol(T, Decl(reverseMappedUnionInference.ts, 5, 20))
|
||||
>Result : Symbol(Result, Decl(reverseMappedUnionInference.ts, 5, 22))
|
||||
|
||||
matches: (node: unknown) => node is T;
|
||||
>matches : Symbol(Extractor.matches, Decl(reverseMappedUnionInference.ts, 5, 32))
|
||||
>node : Symbol(node, Decl(reverseMappedUnionInference.ts, 6, 12))
|
||||
>node : Symbol(node, Decl(reverseMappedUnionInference.ts, 6, 12))
|
||||
>T : Symbol(T, Decl(reverseMappedUnionInference.ts, 5, 20))
|
||||
|
||||
extract: (node: T) => Result | undefined;
|
||||
>extract : Symbol(Extractor.extract, Decl(reverseMappedUnionInference.ts, 6, 40))
|
||||
>node : Symbol(node, Decl(reverseMappedUnionInference.ts, 7, 12))
|
||||
>T : Symbol(T, Decl(reverseMappedUnionInference.ts, 5, 20))
|
||||
>Result : Symbol(Result, Decl(reverseMappedUnionInference.ts, 5, 22))
|
||||
}
|
||||
|
||||
declare function createExtractor<T, Result>(params: {
|
||||
>createExtractor : Symbol(createExtractor, Decl(reverseMappedUnionInference.ts, 8, 1))
|
||||
>T : Symbol(T, Decl(reverseMappedUnionInference.ts, 10, 33))
|
||||
>Result : Symbol(Result, Decl(reverseMappedUnionInference.ts, 10, 35))
|
||||
>params : Symbol(params, Decl(reverseMappedUnionInference.ts, 10, 44))
|
||||
|
||||
matcher: (node: unknown) => node is T;
|
||||
>matcher : Symbol(matcher, Decl(reverseMappedUnionInference.ts, 10, 53))
|
||||
>node : Symbol(node, Decl(reverseMappedUnionInference.ts, 11, 12))
|
||||
>node : Symbol(node, Decl(reverseMappedUnionInference.ts, 11, 12))
|
||||
>T : Symbol(T, Decl(reverseMappedUnionInference.ts, 10, 33))
|
||||
|
||||
extract: (node: T) => Result;
|
||||
>extract : Symbol(extract, Decl(reverseMappedUnionInference.ts, 11, 40))
|
||||
>node : Symbol(node, Decl(reverseMappedUnionInference.ts, 12, 12))
|
||||
>T : Symbol(T, Decl(reverseMappedUnionInference.ts, 10, 33))
|
||||
>Result : Symbol(Result, Decl(reverseMappedUnionInference.ts, 10, 35))
|
||||
|
||||
}): Extractor<T, Result>;
|
||||
>Extractor : Symbol(Extractor, Decl(reverseMappedUnionInference.ts, 3, 1))
|
||||
>T : Symbol(T, Decl(reverseMappedUnionInference.ts, 10, 33))
|
||||
>Result : Symbol(Result, Decl(reverseMappedUnionInference.ts, 10, 35))
|
||||
|
||||
interface Identifier {
|
||||
>Identifier : Symbol(Identifier, Decl(reverseMappedUnionInference.ts, 13, 25))
|
||||
|
||||
kind: "identifier";
|
||||
>kind : Symbol(Identifier.kind, Decl(reverseMappedUnionInference.ts, 15, 22))
|
||||
|
||||
name: string;
|
||||
>name : Symbol(Identifier.name, Decl(reverseMappedUnionInference.ts, 16, 21))
|
||||
}
|
||||
|
||||
declare function isIdentifier(node: unknown): node is Identifier;
|
||||
>isIdentifier : Symbol(isIdentifier, Decl(reverseMappedUnionInference.ts, 18, 1))
|
||||
>node : Symbol(node, Decl(reverseMappedUnionInference.ts, 20, 30))
|
||||
>node : Symbol(node, Decl(reverseMappedUnionInference.ts, 20, 30))
|
||||
>Identifier : Symbol(Identifier, Decl(reverseMappedUnionInference.ts, 13, 25))
|
||||
|
||||
const identifierExtractor = createExtractor({
|
||||
>identifierExtractor : Symbol(identifierExtractor, Decl(reverseMappedUnionInference.ts, 22, 5))
|
||||
>createExtractor : Symbol(createExtractor, Decl(reverseMappedUnionInference.ts, 8, 1))
|
||||
|
||||
matcher: isIdentifier,
|
||||
>matcher : Symbol(matcher, Decl(reverseMappedUnionInference.ts, 22, 45))
|
||||
>isIdentifier : Symbol(isIdentifier, Decl(reverseMappedUnionInference.ts, 18, 1))
|
||||
|
||||
extract: (node) => {
|
||||
>extract : Symbol(extract, Decl(reverseMappedUnionInference.ts, 23, 24))
|
||||
>node : Symbol(node, Decl(reverseMappedUnionInference.ts, 24, 12))
|
||||
|
||||
return {
|
||||
node,
|
||||
>node : Symbol(node, Decl(reverseMappedUnionInference.ts, 25, 12))
|
||||
|
||||
kind: "identifier" as const,
|
||||
>kind : Symbol(kind, Decl(reverseMappedUnionInference.ts, 26, 11))
|
||||
>const : Symbol(const)
|
||||
|
||||
value: node.name,
|
||||
>value : Symbol(value, Decl(reverseMappedUnionInference.ts, 27, 34))
|
||||
>node.name : Symbol(Identifier.name, Decl(reverseMappedUnionInference.ts, 16, 21))
|
||||
>node : Symbol(node, Decl(reverseMappedUnionInference.ts, 24, 12))
|
||||
>name : Symbol(Identifier.name, Decl(reverseMappedUnionInference.ts, 16, 21))
|
||||
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
interface StringLiteral {
|
||||
>StringLiteral : Symbol(StringLiteral, Decl(reverseMappedUnionInference.ts, 31, 3))
|
||||
|
||||
kind: "stringLiteral";
|
||||
>kind : Symbol(StringLiteral.kind, Decl(reverseMappedUnionInference.ts, 33, 25))
|
||||
|
||||
value: string;
|
||||
>value : Symbol(StringLiteral.value, Decl(reverseMappedUnionInference.ts, 34, 24))
|
||||
}
|
||||
|
||||
declare function isStringLiteral(node: unknown): node is StringLiteral;
|
||||
>isStringLiteral : Symbol(isStringLiteral, Decl(reverseMappedUnionInference.ts, 36, 1))
|
||||
>node : Symbol(node, Decl(reverseMappedUnionInference.ts, 38, 33))
|
||||
>node : Symbol(node, Decl(reverseMappedUnionInference.ts, 38, 33))
|
||||
>StringLiteral : Symbol(StringLiteral, Decl(reverseMappedUnionInference.ts, 31, 3))
|
||||
|
||||
const stringExtractor = createExtractor({
|
||||
>stringExtractor : Symbol(stringExtractor, Decl(reverseMappedUnionInference.ts, 40, 5))
|
||||
>createExtractor : Symbol(createExtractor, Decl(reverseMappedUnionInference.ts, 8, 1))
|
||||
|
||||
matcher: isStringLiteral,
|
||||
>matcher : Symbol(matcher, Decl(reverseMappedUnionInference.ts, 40, 41))
|
||||
>isStringLiteral : Symbol(isStringLiteral, Decl(reverseMappedUnionInference.ts, 36, 1))
|
||||
|
||||
extract: (node) => {
|
||||
>extract : Symbol(extract, Decl(reverseMappedUnionInference.ts, 41, 27))
|
||||
>node : Symbol(node, Decl(reverseMappedUnionInference.ts, 42, 12))
|
||||
|
||||
return {
|
||||
node,
|
||||
>node : Symbol(node, Decl(reverseMappedUnionInference.ts, 43, 12))
|
||||
|
||||
kind: "string" as const,
|
||||
>kind : Symbol(kind, Decl(reverseMappedUnionInference.ts, 44, 11))
|
||||
>const : Symbol(const)
|
||||
|
||||
value: node.value,
|
||||
>value : Symbol(value, Decl(reverseMappedUnionInference.ts, 45, 30))
|
||||
>node.value : Symbol(StringLiteral.value, Decl(reverseMappedUnionInference.ts, 34, 24))
|
||||
>node : Symbol(node, Decl(reverseMappedUnionInference.ts, 42, 12))
|
||||
>value : Symbol(StringLiteral.value, Decl(reverseMappedUnionInference.ts, 34, 24))
|
||||
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
declare function unionType<Result extends readonly unknown[]>(parsers: {
|
||||
>unionType : Symbol(unionType, Decl(reverseMappedUnionInference.ts, 49, 3))
|
||||
>Result : Symbol(Result, Decl(reverseMappedUnionInference.ts, 51, 27))
|
||||
>parsers : Symbol(parsers, Decl(reverseMappedUnionInference.ts, 51, 62))
|
||||
|
||||
[K in keyof Result]: AnyExtractor<Result[K]>;
|
||||
>K : Symbol(K, Decl(reverseMappedUnionInference.ts, 52, 3))
|
||||
>Result : Symbol(Result, Decl(reverseMappedUnionInference.ts, 51, 27))
|
||||
>AnyExtractor : Symbol(AnyExtractor, Decl(reverseMappedUnionInference.ts, 0, 0))
|
||||
>Result : Symbol(Result, Decl(reverseMappedUnionInference.ts, 51, 27))
|
||||
>K : Symbol(K, Decl(reverseMappedUnionInference.ts, 52, 3))
|
||||
|
||||
}): AnyExtractor<Result[number]>;
|
||||
>AnyExtractor : Symbol(AnyExtractor, Decl(reverseMappedUnionInference.ts, 0, 0))
|
||||
>Result : Symbol(Result, Decl(reverseMappedUnionInference.ts, 51, 27))
|
||||
|
||||
const myUnion = unionType([identifierExtractor, stringExtractor]);
|
||||
>myUnion : Symbol(myUnion, Decl(reverseMappedUnionInference.ts, 55, 5))
|
||||
>unionType : Symbol(unionType, Decl(reverseMappedUnionInference.ts, 49, 3))
|
||||
>identifierExtractor : Symbol(identifierExtractor, Decl(reverseMappedUnionInference.ts, 22, 5))
|
||||
>stringExtractor : Symbol(stringExtractor, Decl(reverseMappedUnionInference.ts, 40, 5))
|
||||
|
||||
148
tests/baselines/reference/reverseMappedUnionInference.types
Normal file
148
tests/baselines/reference/reverseMappedUnionInference.types
Normal file
@ -0,0 +1,148 @@
|
||||
//// [tests/cases/compiler/reverseMappedUnionInference.ts] ////
|
||||
|
||||
=== reverseMappedUnionInference.ts ===
|
||||
interface AnyExtractor<Result> {
|
||||
matches: (node: any) => boolean;
|
||||
>matches : (node: any) => boolean
|
||||
>node : any
|
||||
|
||||
extract: (node: any) => Result | undefined;
|
||||
>extract : (node: any) => Result | undefined
|
||||
>node : any
|
||||
}
|
||||
|
||||
interface Extractor<T, Result> {
|
||||
matches: (node: unknown) => node is T;
|
||||
>matches : (node: unknown) => node is T
|
||||
>node : unknown
|
||||
|
||||
extract: (node: T) => Result | undefined;
|
||||
>extract : (node: T) => Result | undefined
|
||||
>node : T
|
||||
}
|
||||
|
||||
declare function createExtractor<T, Result>(params: {
|
||||
>createExtractor : <T, Result>(params: { matcher: (node: unknown) => node is T; extract: (node: T) => Result; }) => Extractor<T, Result>
|
||||
>params : { matcher: (node: unknown) => node is T; extract: (node: T) => Result; }
|
||||
|
||||
matcher: (node: unknown) => node is T;
|
||||
>matcher : (node: unknown) => node is T
|
||||
>node : unknown
|
||||
|
||||
extract: (node: T) => Result;
|
||||
>extract : (node: T) => Result
|
||||
>node : T
|
||||
|
||||
}): Extractor<T, Result>;
|
||||
|
||||
interface Identifier {
|
||||
kind: "identifier";
|
||||
>kind : "identifier"
|
||||
|
||||
name: string;
|
||||
>name : string
|
||||
}
|
||||
|
||||
declare function isIdentifier(node: unknown): node is Identifier;
|
||||
>isIdentifier : (node: unknown) => node is Identifier
|
||||
>node : unknown
|
||||
|
||||
const identifierExtractor = createExtractor({
|
||||
>identifierExtractor : Extractor<Identifier, { node: Identifier; kind: "identifier"; value: string; }>
|
||||
>createExtractor({ matcher: isIdentifier, extract: (node) => { return { node, kind: "identifier" as const, value: node.name, }; },}) : Extractor<Identifier, { node: Identifier; kind: "identifier"; value: string; }>
|
||||
>createExtractor : <T, Result>(params: { matcher: (node: unknown) => node is T; extract: (node: T) => Result; }) => Extractor<T, Result>
|
||||
>{ matcher: isIdentifier, extract: (node) => { return { node, kind: "identifier" as const, value: node.name, }; },} : { matcher: (node: unknown) => node is Identifier; extract: (node: Identifier) => { node: Identifier; kind: "identifier"; value: string; }; }
|
||||
|
||||
matcher: isIdentifier,
|
||||
>matcher : (node: unknown) => node is Identifier
|
||||
>isIdentifier : (node: unknown) => node is Identifier
|
||||
|
||||
extract: (node) => {
|
||||
>extract : (node: Identifier) => { node: Identifier; kind: "identifier"; value: string; }
|
||||
>(node) => { return { node, kind: "identifier" as const, value: node.name, }; } : (node: Identifier) => { node: Identifier; kind: "identifier"; value: string; }
|
||||
>node : Identifier
|
||||
|
||||
return {
|
||||
>{ node, kind: "identifier" as const, value: node.name, } : { node: Identifier; kind: "identifier"; value: string; }
|
||||
|
||||
node,
|
||||
>node : Identifier
|
||||
|
||||
kind: "identifier" as const,
|
||||
>kind : "identifier"
|
||||
>"identifier" as const : "identifier"
|
||||
>"identifier" : "identifier"
|
||||
|
||||
value: node.name,
|
||||
>value : string
|
||||
>node.name : string
|
||||
>node : Identifier
|
||||
>name : string
|
||||
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
interface StringLiteral {
|
||||
kind: "stringLiteral";
|
||||
>kind : "stringLiteral"
|
||||
|
||||
value: string;
|
||||
>value : string
|
||||
}
|
||||
|
||||
declare function isStringLiteral(node: unknown): node is StringLiteral;
|
||||
>isStringLiteral : (node: unknown) => node is StringLiteral
|
||||
>node : unknown
|
||||
|
||||
const stringExtractor = createExtractor({
|
||||
>stringExtractor : Extractor<StringLiteral, { node: StringLiteral; kind: "string"; value: string; }>
|
||||
>createExtractor({ matcher: isStringLiteral, extract: (node) => { return { node, kind: "string" as const, value: node.value, }; },}) : Extractor<StringLiteral, { node: StringLiteral; kind: "string"; value: string; }>
|
||||
>createExtractor : <T, Result>(params: { matcher: (node: unknown) => node is T; extract: (node: T) => Result; }) => Extractor<T, Result>
|
||||
>{ matcher: isStringLiteral, extract: (node) => { return { node, kind: "string" as const, value: node.value, }; },} : { matcher: (node: unknown) => node is StringLiteral; extract: (node: StringLiteral) => { node: StringLiteral; kind: "string"; value: string; }; }
|
||||
|
||||
matcher: isStringLiteral,
|
||||
>matcher : (node: unknown) => node is StringLiteral
|
||||
>isStringLiteral : (node: unknown) => node is StringLiteral
|
||||
|
||||
extract: (node) => {
|
||||
>extract : (node: StringLiteral) => { node: StringLiteral; kind: "string"; value: string; }
|
||||
>(node) => { return { node, kind: "string" as const, value: node.value, }; } : (node: StringLiteral) => { node: StringLiteral; kind: "string"; value: string; }
|
||||
>node : StringLiteral
|
||||
|
||||
return {
|
||||
>{ node, kind: "string" as const, value: node.value, } : { node: StringLiteral; kind: "string"; value: string; }
|
||||
|
||||
node,
|
||||
>node : StringLiteral
|
||||
|
||||
kind: "string" as const,
|
||||
>kind : "string"
|
||||
>"string" as const : "string"
|
||||
>"string" : "string"
|
||||
|
||||
value: node.value,
|
||||
>value : string
|
||||
>node.value : string
|
||||
>node : StringLiteral
|
||||
>value : string
|
||||
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
declare function unionType<Result extends readonly unknown[]>(parsers: {
|
||||
>unionType : <Result extends readonly unknown[]>(parsers: { [K in keyof Result]: AnyExtractor<Result[K]>; }) => AnyExtractor<Result[number]>
|
||||
>parsers : { [K in keyof Result]: AnyExtractor<Result[K]>; }
|
||||
|
||||
[K in keyof Result]: AnyExtractor<Result[K]>;
|
||||
}): AnyExtractor<Result[number]>;
|
||||
|
||||
const myUnion = unionType([identifierExtractor, stringExtractor]);
|
||||
>myUnion : AnyExtractor<{ node: Identifier; kind: "identifier"; value: string; } | { node: StringLiteral; kind: "string"; value: string; }>
|
||||
>unionType([identifierExtractor, stringExtractor]) : AnyExtractor<{ node: Identifier; kind: "identifier"; value: string; } | { node: StringLiteral; kind: "string"; value: string; }>
|
||||
>unionType : <Result extends readonly unknown[]>(parsers: { [K in keyof Result]: AnyExtractor<Result[K]>; }) => AnyExtractor<Result[number]>
|
||||
>[identifierExtractor, stringExtractor] : (Extractor<Identifier, { node: Identifier; kind: "identifier"; value: string; }> | Extractor<StringLiteral, { node: StringLiteral; kind: "string"; value: string; }>)[]
|
||||
>identifierExtractor : Extractor<Identifier, { node: Identifier; kind: "identifier"; value: string; }>
|
||||
>stringExtractor : Extractor<StringLiteral, { node: StringLiteral; kind: "string"; value: string; }>
|
||||
|
||||
59
tests/cases/compiler/reverseMappedUnionInference.ts
Normal file
59
tests/cases/compiler/reverseMappedUnionInference.ts
Normal file
@ -0,0 +1,59 @@
|
||||
// @strict: true
|
||||
// @noEmit: true
|
||||
|
||||
interface AnyExtractor<Result> {
|
||||
matches: (node: any) => boolean;
|
||||
extract: (node: any) => Result | undefined;
|
||||
}
|
||||
|
||||
interface Extractor<T, Result> {
|
||||
matches: (node: unknown) => node is T;
|
||||
extract: (node: T) => Result | undefined;
|
||||
}
|
||||
|
||||
declare function createExtractor<T, Result>(params: {
|
||||
matcher: (node: unknown) => node is T;
|
||||
extract: (node: T) => Result;
|
||||
}): Extractor<T, Result>;
|
||||
|
||||
interface Identifier {
|
||||
kind: "identifier";
|
||||
name: string;
|
||||
}
|
||||
|
||||
declare function isIdentifier(node: unknown): node is Identifier;
|
||||
|
||||
const identifierExtractor = createExtractor({
|
||||
matcher: isIdentifier,
|
||||
extract: (node) => {
|
||||
return {
|
||||
node,
|
||||
kind: "identifier" as const,
|
||||
value: node.name,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
interface StringLiteral {
|
||||
kind: "stringLiteral";
|
||||
value: string;
|
||||
}
|
||||
|
||||
declare function isStringLiteral(node: unknown): node is StringLiteral;
|
||||
|
||||
const stringExtractor = createExtractor({
|
||||
matcher: isStringLiteral,
|
||||
extract: (node) => {
|
||||
return {
|
||||
node,
|
||||
kind: "string" as const,
|
||||
value: node.value,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
declare function unionType<Result extends readonly unknown[]>(parsers: {
|
||||
[K in keyof Result]: AnyExtractor<Result[K]>;
|
||||
}): AnyExtractor<Result[number]>;
|
||||
|
||||
const myUnion = unionType([identifierExtractor, stringExtractor]);
|
||||
Loading…
x
Reference in New Issue
Block a user