mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-08 18:11:45 -06:00
Combine keyof T inferences (#22525)
* Combine keyof T inferences * Extract covariant inference derivation into function * Test:keyof inference lower priority than return inference for #22376 * Update 'expected' comment in keyofInferenceLowerPriorityThanReturn * Update comment in test too, not just baselines * Fix typo * Move tests
This commit is contained in:
parent
a11e54856a
commit
044cdbc85f
@ -11737,7 +11737,10 @@ namespace ts {
|
||||
else if ((isLiteralType(source) || source.flags & TypeFlags.String) && target.flags & TypeFlags.Index) {
|
||||
const empty = createEmptyObjectTypeFromStringLiteral(source);
|
||||
contravariant = !contravariant;
|
||||
const savePriority = priority;
|
||||
priority |= InferencePriority.LiteralKeyof;
|
||||
inferFromTypes(empty, (target as IndexType).type);
|
||||
priority = savePriority;
|
||||
contravariant = !contravariant;
|
||||
}
|
||||
else if (source.flags & TypeFlags.IndexedAccess && target.flags & TypeFlags.IndexedAccess) {
|
||||
@ -11980,6 +11983,30 @@ namespace ts {
|
||||
return candidates;
|
||||
}
|
||||
|
||||
function getContravariantInference(inference: InferenceInfo) {
|
||||
return inference.priority & InferencePriority.PriorityImpliesCombination ? getIntersectionType(inference.contraCandidates) : getCommonSubtype(inference.contraCandidates);
|
||||
}
|
||||
|
||||
function getCovariantInference(inference: InferenceInfo, context: InferenceContext, signature: Signature) {
|
||||
// Extract all object literal types and replace them with a single widened and normalized type.
|
||||
const candidates = widenObjectLiteralCandidates(inference.candidates);
|
||||
// We widen inferred literal types if
|
||||
// all inferences were made to top-level occurrences of the type parameter, and
|
||||
// the type parameter has no constraint or its constraint includes no primitive or literal types, and
|
||||
// the type parameter was fixed during inference or does not occur at top-level in the return type.
|
||||
const widenLiteralTypes = inference.topLevel &&
|
||||
!hasPrimitiveConstraint(inference.typeParameter) &&
|
||||
(inference.isFixed || !isTypeParameterAtTopLevel(getReturnTypeOfSignature(signature), inference.typeParameter));
|
||||
const baseCandidates = widenLiteralTypes ? sameMap(candidates, getWidenedLiteralType) : candidates;
|
||||
// If all inferences were made from contravariant positions, infer a common subtype. Otherwise, if
|
||||
// union types were requested or if all inferences were made from the return type position, infer a
|
||||
// union type. Otherwise, infer a common supertype.
|
||||
const unwidenedType = context.flags & InferenceFlags.InferUnionTypes || inference.priority & InferencePriority.PriorityImpliesCombination ?
|
||||
getUnionType(baseCandidates, UnionReduction.Subtype) :
|
||||
getCommonSupertype(baseCandidates);
|
||||
return getWidenedType(unwidenedType);
|
||||
}
|
||||
|
||||
function getInferredType(context: InferenceContext, index: number): Type {
|
||||
const inference = context.inferences[index];
|
||||
let inferredType = inference.inferredType;
|
||||
@ -11987,32 +12014,16 @@ namespace ts {
|
||||
const signature = context.signature;
|
||||
if (signature) {
|
||||
if (inference.candidates) {
|
||||
// Extract all object literal types and replace them with a single widened and normalized type.
|
||||
const candidates = widenObjectLiteralCandidates(inference.candidates);
|
||||
// We widen inferred literal types if
|
||||
// all inferences were made to top-level ocurrences of the type parameter, and
|
||||
// the type parameter has no constraint or its constraint includes no primitive or literal types, and
|
||||
// the type parameter was fixed during inference or does not occur at top-level in the return type.
|
||||
const widenLiteralTypes = inference.topLevel &&
|
||||
!hasPrimitiveConstraint(inference.typeParameter) &&
|
||||
(inference.isFixed || !isTypeParameterAtTopLevel(getReturnTypeOfSignature(signature), inference.typeParameter));
|
||||
const baseCandidates = widenLiteralTypes ? sameMap(candidates, getWidenedLiteralType) : candidates;
|
||||
// If all inferences were made from contravariant positions, infer a common subtype. Otherwise, if
|
||||
// union types were requested or if all inferences were made from the return type position, infer a
|
||||
// union type. Otherwise, infer a common supertype.
|
||||
const unwidenedType = context.flags & InferenceFlags.InferUnionTypes || inference.priority & InferencePriority.PriorityImpliesUnion ?
|
||||
getUnionType(baseCandidates, UnionReduction.Subtype) :
|
||||
getCommonSupertype(baseCandidates);
|
||||
inferredType = getWidenedType(unwidenedType);
|
||||
inferredType = getCovariantInference(inference, context, signature);
|
||||
// If we have inferred 'never' but have contravariant candidates. To get a more specific type we
|
||||
// infer from the contravariant candidates instead.
|
||||
if (inferredType.flags & TypeFlags.Never && inference.contraCandidates) {
|
||||
inferredType = getCommonSubtype(inference.contraCandidates);
|
||||
inferredType = getContravariantInference(inference);
|
||||
}
|
||||
}
|
||||
else if (inference.contraCandidates) {
|
||||
// We only have contravariant inferences, infer the best common subtype of those
|
||||
inferredType = getCommonSubtype(inference.contraCandidates);
|
||||
inferredType = getContravariantInference(inference);
|
||||
}
|
||||
else if (context.flags & InferenceFlags.NoDefault) {
|
||||
// We use silentNeverType as the wildcard that signals no inferences.
|
||||
|
||||
@ -3920,10 +3920,11 @@ namespace ts {
|
||||
HomomorphicMappedType = 1 << 1, // Reverse inference for homomorphic mapped type
|
||||
MappedTypeConstraint = 1 << 2, // Reverse inference for mapped type
|
||||
ReturnType = 1 << 3, // Inference made from return type of generic function
|
||||
NoConstraints = 1 << 4, // Don't infer from constraints of instantiable types
|
||||
AlwaysStrict = 1 << 5, // Always use strict rules for contravariant inferences
|
||||
LiteralKeyof = 1 << 4, // Inference made from a string literal to a keyof T
|
||||
NoConstraints = 1 << 5, // Don't infer from constraints of instantiable types
|
||||
AlwaysStrict = 1 << 6, // Always use strict rules for contravariant inferences
|
||||
|
||||
PriorityImpliesUnion = ReturnType | MappedTypeConstraint, // These priorities imply that the resulting type should be a union of all candidates
|
||||
PriorityImpliesCombination = ReturnType | MappedTypeConstraint | LiteralKeyof, // These priorities imply that the resulting type should be a combination of all candidates
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
|
||||
@ -2240,9 +2240,10 @@ declare namespace ts {
|
||||
HomomorphicMappedType = 2,
|
||||
MappedTypeConstraint = 4,
|
||||
ReturnType = 8,
|
||||
NoConstraints = 16,
|
||||
AlwaysStrict = 32,
|
||||
PriorityImpliesUnion = 12,
|
||||
LiteralKeyof = 16,
|
||||
NoConstraints = 32,
|
||||
AlwaysStrict = 64,
|
||||
PriorityImpliesCombination = 28,
|
||||
}
|
||||
interface JsFileExtensionInfo {
|
||||
extension: string;
|
||||
|
||||
@ -2240,9 +2240,10 @@ declare namespace ts {
|
||||
HomomorphicMappedType = 2,
|
||||
MappedTypeConstraint = 4,
|
||||
ReturnType = 8,
|
||||
NoConstraints = 16,
|
||||
AlwaysStrict = 32,
|
||||
PriorityImpliesUnion = 12,
|
||||
LiteralKeyof = 16,
|
||||
NoConstraints = 32,
|
||||
AlwaysStrict = 64,
|
||||
PriorityImpliesCombination = 28,
|
||||
}
|
||||
interface JsFileExtensionInfo {
|
||||
extension: string;
|
||||
|
||||
17
tests/baselines/reference/keyofInferenceIntersectsResults.js
Normal file
17
tests/baselines/reference/keyofInferenceIntersectsResults.js
Normal file
@ -0,0 +1,17 @@
|
||||
//// [keyofInferenceIntersectsResults.ts]
|
||||
interface X {
|
||||
a: string;
|
||||
b: string;
|
||||
}
|
||||
|
||||
declare function foo<T = X>(x: keyof T, y: keyof T): T;
|
||||
declare function bar<T>(x: keyof T, y: keyof T): T;
|
||||
|
||||
const a = foo<X>('a', 'b'); // compiles cleanly
|
||||
const b = foo('a', 'b'); // also clean
|
||||
const c = bar('a', 'b'); // still clean
|
||||
|
||||
//// [keyofInferenceIntersectsResults.js]
|
||||
var a = foo('a', 'b'); // compiles cleanly
|
||||
var b = foo('a', 'b'); // also clean
|
||||
var c = bar('a', 'b'); // still clean
|
||||
@ -0,0 +1,43 @@
|
||||
=== tests/cases/conformance/types/typeRelationships/typeInference/keyofInferenceIntersectsResults.ts ===
|
||||
interface X {
|
||||
>X : Symbol(X, Decl(keyofInferenceIntersectsResults.ts, 0, 0))
|
||||
|
||||
a: string;
|
||||
>a : Symbol(X.a, Decl(keyofInferenceIntersectsResults.ts, 0, 13))
|
||||
|
||||
b: string;
|
||||
>b : Symbol(X.b, Decl(keyofInferenceIntersectsResults.ts, 1, 14))
|
||||
}
|
||||
|
||||
declare function foo<T = X>(x: keyof T, y: keyof T): T;
|
||||
>foo : Symbol(foo, Decl(keyofInferenceIntersectsResults.ts, 3, 1))
|
||||
>T : Symbol(T, Decl(keyofInferenceIntersectsResults.ts, 5, 21))
|
||||
>X : Symbol(X, Decl(keyofInferenceIntersectsResults.ts, 0, 0))
|
||||
>x : Symbol(x, Decl(keyofInferenceIntersectsResults.ts, 5, 28))
|
||||
>T : Symbol(T, Decl(keyofInferenceIntersectsResults.ts, 5, 21))
|
||||
>y : Symbol(y, Decl(keyofInferenceIntersectsResults.ts, 5, 39))
|
||||
>T : Symbol(T, Decl(keyofInferenceIntersectsResults.ts, 5, 21))
|
||||
>T : Symbol(T, Decl(keyofInferenceIntersectsResults.ts, 5, 21))
|
||||
|
||||
declare function bar<T>(x: keyof T, y: keyof T): T;
|
||||
>bar : Symbol(bar, Decl(keyofInferenceIntersectsResults.ts, 5, 55))
|
||||
>T : Symbol(T, Decl(keyofInferenceIntersectsResults.ts, 6, 21))
|
||||
>x : Symbol(x, Decl(keyofInferenceIntersectsResults.ts, 6, 24))
|
||||
>T : Symbol(T, Decl(keyofInferenceIntersectsResults.ts, 6, 21))
|
||||
>y : Symbol(y, Decl(keyofInferenceIntersectsResults.ts, 6, 35))
|
||||
>T : Symbol(T, Decl(keyofInferenceIntersectsResults.ts, 6, 21))
|
||||
>T : Symbol(T, Decl(keyofInferenceIntersectsResults.ts, 6, 21))
|
||||
|
||||
const a = foo<X>('a', 'b'); // compiles cleanly
|
||||
>a : Symbol(a, Decl(keyofInferenceIntersectsResults.ts, 8, 5))
|
||||
>foo : Symbol(foo, Decl(keyofInferenceIntersectsResults.ts, 3, 1))
|
||||
>X : Symbol(X, Decl(keyofInferenceIntersectsResults.ts, 0, 0))
|
||||
|
||||
const b = foo('a', 'b'); // also clean
|
||||
>b : Symbol(b, Decl(keyofInferenceIntersectsResults.ts, 9, 5))
|
||||
>foo : Symbol(foo, Decl(keyofInferenceIntersectsResults.ts, 3, 1))
|
||||
|
||||
const c = bar('a', 'b'); // still clean
|
||||
>c : Symbol(c, Decl(keyofInferenceIntersectsResults.ts, 10, 5))
|
||||
>bar : Symbol(bar, Decl(keyofInferenceIntersectsResults.ts, 5, 55))
|
||||
|
||||
@ -0,0 +1,52 @@
|
||||
=== tests/cases/conformance/types/typeRelationships/typeInference/keyofInferenceIntersectsResults.ts ===
|
||||
interface X {
|
||||
>X : X
|
||||
|
||||
a: string;
|
||||
>a : string
|
||||
|
||||
b: string;
|
||||
>b : string
|
||||
}
|
||||
|
||||
declare function foo<T = X>(x: keyof T, y: keyof T): T;
|
||||
>foo : <T = X>(x: keyof T, y: keyof T) => T
|
||||
>T : T
|
||||
>X : X
|
||||
>x : keyof T
|
||||
>T : T
|
||||
>y : keyof T
|
||||
>T : T
|
||||
>T : T
|
||||
|
||||
declare function bar<T>(x: keyof T, y: keyof T): T;
|
||||
>bar : <T>(x: keyof T, y: keyof T) => T
|
||||
>T : T
|
||||
>x : keyof T
|
||||
>T : T
|
||||
>y : keyof T
|
||||
>T : T
|
||||
>T : T
|
||||
|
||||
const a = foo<X>('a', 'b'); // compiles cleanly
|
||||
>a : X
|
||||
>foo<X>('a', 'b') : X
|
||||
>foo : <T = X>(x: keyof T, y: keyof T) => T
|
||||
>X : X
|
||||
>'a' : "a"
|
||||
>'b' : "b"
|
||||
|
||||
const b = foo('a', 'b'); // also clean
|
||||
>b : { a: any; } & { b: any; }
|
||||
>foo('a', 'b') : { a: any; } & { b: any; }
|
||||
>foo : <T = X>(x: keyof T, y: keyof T) => T
|
||||
>'a' : "a"
|
||||
>'b' : "b"
|
||||
|
||||
const c = bar('a', 'b'); // still clean
|
||||
>c : { a: any; } & { b: any; }
|
||||
>bar('a', 'b') : { a: any; } & { b: any; }
|
||||
>bar : <T>(x: keyof T, y: keyof T) => T
|
||||
>'a' : "a"
|
||||
>'b' : "b"
|
||||
|
||||
@ -0,0 +1,57 @@
|
||||
//// [keyofInferenceLowerPriorityThanReturn.ts]
|
||||
// #22736
|
||||
declare class Write {
|
||||
protected dummy: Write;
|
||||
}
|
||||
|
||||
declare class Col<s, a> {
|
||||
protected dummy: [Col<s, a>, s, a];
|
||||
}
|
||||
|
||||
declare class Table<Req, Def> {
|
||||
protected dummy: [Table<Req, Def>, Req, Def];
|
||||
}
|
||||
|
||||
type MakeTable<T1 extends object, T2 extends object> = {
|
||||
[P in keyof T1]: Col<Write, T1[P]>;
|
||||
} & {
|
||||
[P in keyof T2]: Col<Write, T2[P]>;
|
||||
};
|
||||
|
||||
declare class ConflictTarget<Cols> {
|
||||
public static tableColumns<Cols>(cols: (keyof Cols)[]): ConflictTarget<Cols>;
|
||||
protected dummy: [ConflictTarget<Cols>, Cols];
|
||||
}
|
||||
|
||||
|
||||
|
||||
const bookTable: Table<BookReq, BookDef> = null as any
|
||||
|
||||
interface BookReq {
|
||||
readonly title: string;
|
||||
readonly serial: number;
|
||||
}
|
||||
|
||||
interface BookDef {
|
||||
readonly author: string;
|
||||
readonly numPages: number | null;
|
||||
}
|
||||
|
||||
|
||||
function insertOnConflictDoNothing<Req extends object, Def extends object>(_table: Table<Req, Def>, _conflictTarget: ConflictTarget<Req & Def>): boolean {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
function f() {
|
||||
insertOnConflictDoNothing(bookTable, ConflictTarget.tableColumns(["serial"])); // <-- No error here; should use the type inferred for the return type of `tableColumns`
|
||||
}
|
||||
|
||||
|
||||
//// [keyofInferenceLowerPriorityThanReturn.js]
|
||||
var bookTable = null;
|
||||
function insertOnConflictDoNothing(_table, _conflictTarget) {
|
||||
throw new Error();
|
||||
}
|
||||
function f() {
|
||||
insertOnConflictDoNothing(bookTable, ConflictTarget.tableColumns(["serial"])); // <-- No error here; should use the type inferred for the return type of `tableColumns`
|
||||
}
|
||||
@ -0,0 +1,138 @@
|
||||
=== tests/cases/conformance/types/typeRelationships/typeInference/keyofInferenceLowerPriorityThanReturn.ts ===
|
||||
// #22736
|
||||
declare class Write {
|
||||
>Write : Symbol(Write, Decl(keyofInferenceLowerPriorityThanReturn.ts, 0, 0))
|
||||
|
||||
protected dummy: Write;
|
||||
>dummy : Symbol(Write.dummy, Decl(keyofInferenceLowerPriorityThanReturn.ts, 1, 21))
|
||||
>Write : Symbol(Write, Decl(keyofInferenceLowerPriorityThanReturn.ts, 0, 0))
|
||||
}
|
||||
|
||||
declare class Col<s, a> {
|
||||
>Col : Symbol(Col, Decl(keyofInferenceLowerPriorityThanReturn.ts, 3, 1))
|
||||
>s : Symbol(s, Decl(keyofInferenceLowerPriorityThanReturn.ts, 5, 18))
|
||||
>a : Symbol(a, Decl(keyofInferenceLowerPriorityThanReturn.ts, 5, 20))
|
||||
|
||||
protected dummy: [Col<s, a>, s, a];
|
||||
>dummy : Symbol(Col.dummy, Decl(keyofInferenceLowerPriorityThanReturn.ts, 5, 25))
|
||||
>Col : Symbol(Col, Decl(keyofInferenceLowerPriorityThanReturn.ts, 3, 1))
|
||||
>s : Symbol(s, Decl(keyofInferenceLowerPriorityThanReturn.ts, 5, 18))
|
||||
>a : Symbol(a, Decl(keyofInferenceLowerPriorityThanReturn.ts, 5, 20))
|
||||
>s : Symbol(s, Decl(keyofInferenceLowerPriorityThanReturn.ts, 5, 18))
|
||||
>a : Symbol(a, Decl(keyofInferenceLowerPriorityThanReturn.ts, 5, 20))
|
||||
}
|
||||
|
||||
declare class Table<Req, Def> {
|
||||
>Table : Symbol(Table, Decl(keyofInferenceLowerPriorityThanReturn.ts, 7, 1))
|
||||
>Req : Symbol(Req, Decl(keyofInferenceLowerPriorityThanReturn.ts, 9, 20))
|
||||
>Def : Symbol(Def, Decl(keyofInferenceLowerPriorityThanReturn.ts, 9, 24))
|
||||
|
||||
protected dummy: [Table<Req, Def>, Req, Def];
|
||||
>dummy : Symbol(Table.dummy, Decl(keyofInferenceLowerPriorityThanReturn.ts, 9, 31))
|
||||
>Table : Symbol(Table, Decl(keyofInferenceLowerPriorityThanReturn.ts, 7, 1))
|
||||
>Req : Symbol(Req, Decl(keyofInferenceLowerPriorityThanReturn.ts, 9, 20))
|
||||
>Def : Symbol(Def, Decl(keyofInferenceLowerPriorityThanReturn.ts, 9, 24))
|
||||
>Req : Symbol(Req, Decl(keyofInferenceLowerPriorityThanReturn.ts, 9, 20))
|
||||
>Def : Symbol(Def, Decl(keyofInferenceLowerPriorityThanReturn.ts, 9, 24))
|
||||
}
|
||||
|
||||
type MakeTable<T1 extends object, T2 extends object> = {
|
||||
>MakeTable : Symbol(MakeTable, Decl(keyofInferenceLowerPriorityThanReturn.ts, 11, 1))
|
||||
>T1 : Symbol(T1, Decl(keyofInferenceLowerPriorityThanReturn.ts, 13, 15))
|
||||
>T2 : Symbol(T2, Decl(keyofInferenceLowerPriorityThanReturn.ts, 13, 33))
|
||||
|
||||
[P in keyof T1]: Col<Write, T1[P]>;
|
||||
>P : Symbol(P, Decl(keyofInferenceLowerPriorityThanReturn.ts, 14, 5))
|
||||
>T1 : Symbol(T1, Decl(keyofInferenceLowerPriorityThanReturn.ts, 13, 15))
|
||||
>Col : Symbol(Col, Decl(keyofInferenceLowerPriorityThanReturn.ts, 3, 1))
|
||||
>Write : Symbol(Write, Decl(keyofInferenceLowerPriorityThanReturn.ts, 0, 0))
|
||||
>T1 : Symbol(T1, Decl(keyofInferenceLowerPriorityThanReturn.ts, 13, 15))
|
||||
>P : Symbol(P, Decl(keyofInferenceLowerPriorityThanReturn.ts, 14, 5))
|
||||
|
||||
} & {
|
||||
[P in keyof T2]: Col<Write, T2[P]>;
|
||||
>P : Symbol(P, Decl(keyofInferenceLowerPriorityThanReturn.ts, 16, 9))
|
||||
>T2 : Symbol(T2, Decl(keyofInferenceLowerPriorityThanReturn.ts, 13, 33))
|
||||
>Col : Symbol(Col, Decl(keyofInferenceLowerPriorityThanReturn.ts, 3, 1))
|
||||
>Write : Symbol(Write, Decl(keyofInferenceLowerPriorityThanReturn.ts, 0, 0))
|
||||
>T2 : Symbol(T2, Decl(keyofInferenceLowerPriorityThanReturn.ts, 13, 33))
|
||||
>P : Symbol(P, Decl(keyofInferenceLowerPriorityThanReturn.ts, 16, 9))
|
||||
|
||||
};
|
||||
|
||||
declare class ConflictTarget<Cols> {
|
||||
>ConflictTarget : Symbol(ConflictTarget, Decl(keyofInferenceLowerPriorityThanReturn.ts, 17, 6))
|
||||
>Cols : Symbol(Cols, Decl(keyofInferenceLowerPriorityThanReturn.ts, 19, 29))
|
||||
|
||||
public static tableColumns<Cols>(cols: (keyof Cols)[]): ConflictTarget<Cols>;
|
||||
>tableColumns : Symbol(ConflictTarget.tableColumns, Decl(keyofInferenceLowerPriorityThanReturn.ts, 19, 36))
|
||||
>Cols : Symbol(Cols, Decl(keyofInferenceLowerPriorityThanReturn.ts, 20, 31))
|
||||
>cols : Symbol(cols, Decl(keyofInferenceLowerPriorityThanReturn.ts, 20, 37))
|
||||
>Cols : Symbol(Cols, Decl(keyofInferenceLowerPriorityThanReturn.ts, 20, 31))
|
||||
>ConflictTarget : Symbol(ConflictTarget, Decl(keyofInferenceLowerPriorityThanReturn.ts, 17, 6))
|
||||
>Cols : Symbol(Cols, Decl(keyofInferenceLowerPriorityThanReturn.ts, 20, 31))
|
||||
|
||||
protected dummy: [ConflictTarget<Cols>, Cols];
|
||||
>dummy : Symbol(ConflictTarget.dummy, Decl(keyofInferenceLowerPriorityThanReturn.ts, 20, 81))
|
||||
>ConflictTarget : Symbol(ConflictTarget, Decl(keyofInferenceLowerPriorityThanReturn.ts, 17, 6))
|
||||
>Cols : Symbol(Cols, Decl(keyofInferenceLowerPriorityThanReturn.ts, 19, 29))
|
||||
>Cols : Symbol(Cols, Decl(keyofInferenceLowerPriorityThanReturn.ts, 19, 29))
|
||||
}
|
||||
|
||||
|
||||
|
||||
const bookTable: Table<BookReq, BookDef> = null as any
|
||||
>bookTable : Symbol(bookTable, Decl(keyofInferenceLowerPriorityThanReturn.ts, 26, 5))
|
||||
>Table : Symbol(Table, Decl(keyofInferenceLowerPriorityThanReturn.ts, 7, 1))
|
||||
>BookReq : Symbol(BookReq, Decl(keyofInferenceLowerPriorityThanReturn.ts, 26, 54))
|
||||
>BookDef : Symbol(BookDef, Decl(keyofInferenceLowerPriorityThanReturn.ts, 31, 1))
|
||||
|
||||
interface BookReq {
|
||||
>BookReq : Symbol(BookReq, Decl(keyofInferenceLowerPriorityThanReturn.ts, 26, 54))
|
||||
|
||||
readonly title: string;
|
||||
>title : Symbol(BookReq.title, Decl(keyofInferenceLowerPriorityThanReturn.ts, 28, 19))
|
||||
|
||||
readonly serial: number;
|
||||
>serial : Symbol(BookReq.serial, Decl(keyofInferenceLowerPriorityThanReturn.ts, 29, 27))
|
||||
}
|
||||
|
||||
interface BookDef {
|
||||
>BookDef : Symbol(BookDef, Decl(keyofInferenceLowerPriorityThanReturn.ts, 31, 1))
|
||||
|
||||
readonly author: string;
|
||||
>author : Symbol(BookDef.author, Decl(keyofInferenceLowerPriorityThanReturn.ts, 33, 19))
|
||||
|
||||
readonly numPages: number | null;
|
||||
>numPages : Symbol(BookDef.numPages, Decl(keyofInferenceLowerPriorityThanReturn.ts, 34, 28))
|
||||
}
|
||||
|
||||
|
||||
function insertOnConflictDoNothing<Req extends object, Def extends object>(_table: Table<Req, Def>, _conflictTarget: ConflictTarget<Req & Def>): boolean {
|
||||
>insertOnConflictDoNothing : Symbol(insertOnConflictDoNothing, Decl(keyofInferenceLowerPriorityThanReturn.ts, 36, 1))
|
||||
>Req : Symbol(Req, Decl(keyofInferenceLowerPriorityThanReturn.ts, 39, 35))
|
||||
>Def : Symbol(Def, Decl(keyofInferenceLowerPriorityThanReturn.ts, 39, 54))
|
||||
>_table : Symbol(_table, Decl(keyofInferenceLowerPriorityThanReturn.ts, 39, 75))
|
||||
>Table : Symbol(Table, Decl(keyofInferenceLowerPriorityThanReturn.ts, 7, 1))
|
||||
>Req : Symbol(Req, Decl(keyofInferenceLowerPriorityThanReturn.ts, 39, 35))
|
||||
>Def : Symbol(Def, Decl(keyofInferenceLowerPriorityThanReturn.ts, 39, 54))
|
||||
>_conflictTarget : Symbol(_conflictTarget, Decl(keyofInferenceLowerPriorityThanReturn.ts, 39, 99))
|
||||
>ConflictTarget : Symbol(ConflictTarget, Decl(keyofInferenceLowerPriorityThanReturn.ts, 17, 6))
|
||||
>Req : Symbol(Req, Decl(keyofInferenceLowerPriorityThanReturn.ts, 39, 35))
|
||||
>Def : Symbol(Def, Decl(keyofInferenceLowerPriorityThanReturn.ts, 39, 54))
|
||||
|
||||
throw new Error();
|
||||
>Error : Symbol(Error, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
}
|
||||
|
||||
function f() {
|
||||
>f : Symbol(f, Decl(keyofInferenceLowerPriorityThanReturn.ts, 41, 1))
|
||||
|
||||
insertOnConflictDoNothing(bookTable, ConflictTarget.tableColumns(["serial"])); // <-- No error here; should use the type inferred for the return type of `tableColumns`
|
||||
>insertOnConflictDoNothing : Symbol(insertOnConflictDoNothing, Decl(keyofInferenceLowerPriorityThanReturn.ts, 36, 1))
|
||||
>bookTable : Symbol(bookTable, Decl(keyofInferenceLowerPriorityThanReturn.ts, 26, 5))
|
||||
>ConflictTarget.tableColumns : Symbol(ConflictTarget.tableColumns, Decl(keyofInferenceLowerPriorityThanReturn.ts, 19, 36))
|
||||
>ConflictTarget : Symbol(ConflictTarget, Decl(keyofInferenceLowerPriorityThanReturn.ts, 17, 6))
|
||||
>tableColumns : Symbol(ConflictTarget.tableColumns, Decl(keyofInferenceLowerPriorityThanReturn.ts, 19, 36))
|
||||
}
|
||||
|
||||
@ -0,0 +1,146 @@
|
||||
=== tests/cases/conformance/types/typeRelationships/typeInference/keyofInferenceLowerPriorityThanReturn.ts ===
|
||||
// #22736
|
||||
declare class Write {
|
||||
>Write : Write
|
||||
|
||||
protected dummy: Write;
|
||||
>dummy : Write
|
||||
>Write : Write
|
||||
}
|
||||
|
||||
declare class Col<s, a> {
|
||||
>Col : Col<s, a>
|
||||
>s : s
|
||||
>a : a
|
||||
|
||||
protected dummy: [Col<s, a>, s, a];
|
||||
>dummy : [Col<s, a>, s, a]
|
||||
>Col : Col<s, a>
|
||||
>s : s
|
||||
>a : a
|
||||
>s : s
|
||||
>a : a
|
||||
}
|
||||
|
||||
declare class Table<Req, Def> {
|
||||
>Table : Table<Req, Def>
|
||||
>Req : Req
|
||||
>Def : Def
|
||||
|
||||
protected dummy: [Table<Req, Def>, Req, Def];
|
||||
>dummy : [Table<Req, Def>, Req, Def]
|
||||
>Table : Table<Req, Def>
|
||||
>Req : Req
|
||||
>Def : Def
|
||||
>Req : Req
|
||||
>Def : Def
|
||||
}
|
||||
|
||||
type MakeTable<T1 extends object, T2 extends object> = {
|
||||
>MakeTable : MakeTable<T1, T2>
|
||||
>T1 : T1
|
||||
>T2 : T2
|
||||
|
||||
[P in keyof T1]: Col<Write, T1[P]>;
|
||||
>P : P
|
||||
>T1 : T1
|
||||
>Col : Col<s, a>
|
||||
>Write : Write
|
||||
>T1 : T1
|
||||
>P : P
|
||||
|
||||
} & {
|
||||
[P in keyof T2]: Col<Write, T2[P]>;
|
||||
>P : P
|
||||
>T2 : T2
|
||||
>Col : Col<s, a>
|
||||
>Write : Write
|
||||
>T2 : T2
|
||||
>P : P
|
||||
|
||||
};
|
||||
|
||||
declare class ConflictTarget<Cols> {
|
||||
>ConflictTarget : ConflictTarget<Cols>
|
||||
>Cols : Cols
|
||||
|
||||
public static tableColumns<Cols>(cols: (keyof Cols)[]): ConflictTarget<Cols>;
|
||||
>tableColumns : <Cols>(cols: (keyof Cols)[]) => ConflictTarget<Cols>
|
||||
>Cols : Cols
|
||||
>cols : (keyof Cols)[]
|
||||
>Cols : Cols
|
||||
>ConflictTarget : ConflictTarget<Cols>
|
||||
>Cols : Cols
|
||||
|
||||
protected dummy: [ConflictTarget<Cols>, Cols];
|
||||
>dummy : [ConflictTarget<Cols>, Cols]
|
||||
>ConflictTarget : ConflictTarget<Cols>
|
||||
>Cols : Cols
|
||||
>Cols : Cols
|
||||
}
|
||||
|
||||
|
||||
|
||||
const bookTable: Table<BookReq, BookDef> = null as any
|
||||
>bookTable : Table<BookReq, BookDef>
|
||||
>Table : Table<Req, Def>
|
||||
>BookReq : BookReq
|
||||
>BookDef : BookDef
|
||||
>null as any : any
|
||||
>null : null
|
||||
|
||||
interface BookReq {
|
||||
>BookReq : BookReq
|
||||
|
||||
readonly title: string;
|
||||
>title : string
|
||||
|
||||
readonly serial: number;
|
||||
>serial : number
|
||||
}
|
||||
|
||||
interface BookDef {
|
||||
>BookDef : BookDef
|
||||
|
||||
readonly author: string;
|
||||
>author : string
|
||||
|
||||
readonly numPages: number | null;
|
||||
>numPages : number
|
||||
>null : null
|
||||
}
|
||||
|
||||
|
||||
function insertOnConflictDoNothing<Req extends object, Def extends object>(_table: Table<Req, Def>, _conflictTarget: ConflictTarget<Req & Def>): boolean {
|
||||
>insertOnConflictDoNothing : <Req extends object, Def extends object>(_table: Table<Req, Def>, _conflictTarget: ConflictTarget<Req & Def>) => boolean
|
||||
>Req : Req
|
||||
>Def : Def
|
||||
>_table : Table<Req, Def>
|
||||
>Table : Table<Req, Def>
|
||||
>Req : Req
|
||||
>Def : Def
|
||||
>_conflictTarget : ConflictTarget<Req & Def>
|
||||
>ConflictTarget : ConflictTarget<Cols>
|
||||
>Req : Req
|
||||
>Def : Def
|
||||
|
||||
throw new Error();
|
||||
>new Error() : Error
|
||||
>Error : ErrorConstructor
|
||||
}
|
||||
|
||||
function f() {
|
||||
>f : () => void
|
||||
|
||||
insertOnConflictDoNothing(bookTable, ConflictTarget.tableColumns(["serial"])); // <-- No error here; should use the type inferred for the return type of `tableColumns`
|
||||
>insertOnConflictDoNothing(bookTable, ConflictTarget.tableColumns(["serial"])) : boolean
|
||||
>insertOnConflictDoNothing : <Req extends object, Def extends object>(_table: Table<Req, Def>, _conflictTarget: ConflictTarget<Req & Def>) => boolean
|
||||
>bookTable : Table<BookReq, BookDef>
|
||||
>ConflictTarget.tableColumns(["serial"]) : ConflictTarget<BookReq & BookDef>
|
||||
>ConflictTarget.tableColumns : <Cols>(cols: (keyof Cols)[]) => ConflictTarget<Cols>
|
||||
>ConflictTarget : typeof ConflictTarget
|
||||
>tableColumns : <Cols>(cols: (keyof Cols)[]) => ConflictTarget<Cols>
|
||||
>["serial"] : "serial"[]
|
||||
>"serial" : "serial"
|
||||
}
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
interface X {
|
||||
a: string;
|
||||
b: string;
|
||||
}
|
||||
|
||||
declare function foo<T = X>(x: keyof T, y: keyof T): T;
|
||||
declare function bar<T>(x: keyof T, y: keyof T): T;
|
||||
|
||||
const a = foo<X>('a', 'b'); // compiles cleanly
|
||||
const b = foo('a', 'b'); // also clean
|
||||
const c = bar('a', 'b'); // still clean
|
||||
@ -0,0 +1,46 @@
|
||||
// #22736
|
||||
declare class Write {
|
||||
protected dummy: Write;
|
||||
}
|
||||
|
||||
declare class Col<s, a> {
|
||||
protected dummy: [Col<s, a>, s, a];
|
||||
}
|
||||
|
||||
declare class Table<Req, Def> {
|
||||
protected dummy: [Table<Req, Def>, Req, Def];
|
||||
}
|
||||
|
||||
type MakeTable<T1 extends object, T2 extends object> = {
|
||||
[P in keyof T1]: Col<Write, T1[P]>;
|
||||
} & {
|
||||
[P in keyof T2]: Col<Write, T2[P]>;
|
||||
};
|
||||
|
||||
declare class ConflictTarget<Cols> {
|
||||
public static tableColumns<Cols>(cols: (keyof Cols)[]): ConflictTarget<Cols>;
|
||||
protected dummy: [ConflictTarget<Cols>, Cols];
|
||||
}
|
||||
|
||||
|
||||
|
||||
const bookTable: Table<BookReq, BookDef> = null as any
|
||||
|
||||
interface BookReq {
|
||||
readonly title: string;
|
||||
readonly serial: number;
|
||||
}
|
||||
|
||||
interface BookDef {
|
||||
readonly author: string;
|
||||
readonly numPages: number | null;
|
||||
}
|
||||
|
||||
|
||||
function insertOnConflictDoNothing<Req extends object, Def extends object>(_table: Table<Req, Def>, _conflictTarget: ConflictTarget<Req & Def>): boolean {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
function f() {
|
||||
insertOnConflictDoNothing(bookTable, ConflictTarget.tableColumns(["serial"])); // <-- No error here; should use the type inferred for the return type of `tableColumns`
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user