Skip to content

Commit dc325fe

Browse files
committed
WIP
1 parent 6ee5490 commit dc325fe

File tree

3 files changed

+76
-36
lines changed

3 files changed

+76
-36
lines changed

src/compiler/checker.ts

Lines changed: 42 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -22403,7 +22403,7 @@ namespace ts {
2240322403
inferFromTypes((source as IndexedAccessType).objectType, (target as IndexedAccessType).objectType);
2240422404
inferFromTypes((source as IndexedAccessType).indexType, (target as IndexedAccessType).indexType);
2240522405
}
22406-
else if (source.flags & TypeFlags.StringMapping && target.flags & TypeFlags.StringMapping) {
22406+
else if (source. flags & TypeFlags.StringMapping && target.flags & TypeFlags.StringMapping) {
2240722407
if ((source as StringMappingType).symbol === (target as StringMappingType).symbol) {
2240822408
inferFromTypes((source as StringMappingType).type, (target as StringMappingType).type);
2240922409
}
@@ -22943,39 +22943,46 @@ namespace ts {
2294322943
if (!inference.inferredType) {
2294422944
let inferredType: Type | undefined;
2294522945
const signature = context.signature;
22946-
if (signature) {
22947-
const inferredCovariantType = inference.candidates ? getCovariantInference(inference, signature) : undefined;
22948-
if (inference.contraCandidates) {
22949-
// If we have both co- and contra-variant inferences, we prefer the contra-variant inference
22950-
// unless the co-variant inference is a subtype of some contra-variant inference and not 'never'.
22951-
inferredType = inferredCovariantType && !(inferredCovariantType.flags & TypeFlags.Never) &&
22952-
some(inference.contraCandidates, t => isTypeSubtypeOf(inferredCovariantType, t)) ?
22953-
inferredCovariantType : getContravariantInference(inference);
22954-
}
22955-
else if (inferredCovariantType) {
22956-
inferredType = inferredCovariantType;
22957-
}
22958-
else if (context.flags & InferenceFlags.NoDefault) {
22959-
// We use silentNeverType as the wildcard that signals no inferences.
22960-
inferredType = silentNeverType;
22946+
if (!(inference.priority! & InferencePriority.BindingPattern)) {
22947+
// Binding pattern inferences provide a contextual type for other inferences,
22948+
// but cannot stand alone - they are expected to be overwritten by another
22949+
// inference with higher priority before fixing. This prevents highly suspicious
22950+
// patterns like `function f<T>(): T; const { foo } = f()` from inferring T as
22951+
// `{ foo: any }`.
22952+
if (signature) {
22953+
const inferredCovariantType = inference.candidates ? getCovariantInference(inference, signature) : undefined;
22954+
if (inference.contraCandidates) {
22955+
// If we have both co- and contra-variant inferences, we prefer the contra-variant inference
22956+
// unless the co-variant inference is a subtype of some contra-variant inference and not 'never'.
22957+
inferredType = inferredCovariantType && !(inferredCovariantType.flags & TypeFlags.Never) &&
22958+
some(inference.contraCandidates, t => isTypeSubtypeOf(inferredCovariantType, t)) ?
22959+
inferredCovariantType : getContravariantInference(inference);
22960+
}
22961+
else if (inferredCovariantType) {
22962+
inferredType = inferredCovariantType;
22963+
}
22964+
else if (context.flags & InferenceFlags.NoDefault) {
22965+
// We use silentNeverType as the wildcard that signals no inferences.
22966+
inferredType = silentNeverType;
22967+
}
22968+
else {
22969+
// Infer either the default or the empty object type when no inferences were
22970+
// made. It is important to remember that in this case, inference still
22971+
// succeeds, meaning there is no error for not having inference candidates. An
22972+
// inference error only occurs when there are *conflicting* candidates, i.e.
22973+
// candidates with no common supertype.
22974+
const defaultType = getDefaultFromTypeParameter(inference.typeParameter);
22975+
if (defaultType) {
22976+
// Instantiate the default type. Any forward reference to a type
22977+
// parameter should be instantiated to the empty object type.
22978+
inferredType = instantiateType(defaultType, mergeTypeMappers(createBackreferenceMapper(context, index), context.nonFixingMapper));
22979+
}
22980+
}
2296122981
}
2296222982
else {
22963-
// Infer either the default or the empty object type when no inferences were
22964-
// made. It is important to remember that in this case, inference still
22965-
// succeeds, meaning there is no error for not having inference candidates. An
22966-
// inference error only occurs when there are *conflicting* candidates, i.e.
22967-
// candidates with no common supertype.
22968-
const defaultType = getDefaultFromTypeParameter(inference.typeParameter);
22969-
if (defaultType) {
22970-
// Instantiate the default type. Any forward reference to a type
22971-
// parameter should be instantiated to the empty object type.
22972-
inferredType = instantiateType(defaultType, mergeTypeMappers(createBackreferenceMapper(context, index), context.nonFixingMapper));
22973-
}
22983+
inferredType = getTypeFromInference(inference);
2297422984
}
2297522985
}
22976-
else {
22977-
inferredType = getTypeFromInference(inference);
22978-
}
2297922986

2298022987
inference.inferredType = inferredType || getDefaultTypeArgumentType(!!(context.flags & InferenceFlags.AnyDefault));
2298122988

@@ -29902,7 +29909,8 @@ namespace ts {
2990229909
// 'let f: (x: string) => number = wrap(s => s.length)', we infer from the declared type of 'f' to the
2990329910
// return type of 'wrap'.
2990429911
if (node.kind !== SyntaxKind.Decorator) {
29905-
const contextualType = getContextualType(node, every(signature.typeParameters, p => !!getDefaultFromTypeParameter(p)) ? ContextFlags.SkipBindingPatterns : ContextFlags.None);
29912+
const skipBindingPatterns = every(signature.typeParameters, p => !!getDefaultFromTypeParameter(p));
29913+
const contextualType = getContextualType(node, skipBindingPatterns ? ContextFlags.SkipBindingPatterns : ContextFlags.None);
2990629914
if (contextualType) {
2990729915
const inferenceTargetType = getReturnTypeOfSignature(signature);
2990829916
if (couldContainTypeVariables(inferenceTargetType)) {
@@ -29924,7 +29932,9 @@ namespace ts {
2992429932
getOrCreateTypeFromSignature(getSignatureInstantiationWithoutFillingInTypeArguments(contextualSignature, contextualSignature.typeParameters)) :
2992529933
instantiatedType;
2992629934
// Inferences made from return types have lower priority than all other inferences.
29927-
inferTypes(context.inferences, inferenceSourceType, inferenceTargetType, InferencePriority.ReturnType);
29935+
const isFromBindingPattern = !skipBindingPatterns && getContextualType(node, ContextFlags.SkipBindingPatterns) !== contextualType;
29936+
const priority = InferencePriority.ReturnType | (isFromBindingPattern ? InferencePriority.BindingPattern : 0);
29937+
inferTypes(context.inferences, inferenceSourceType, inferenceTargetType, priority);
2992829938
// Create a type mapper for instantiating generic contextual types using the inferences made
2992929939
// from the return type. We need a separate inference pass here because (a) instantiation of
2993029940
// the source type uses the outer context's return mapper (which excludes inferences made from

src/compiler/types.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5865,10 +5865,11 @@ namespace ts {
58655865
MappedTypeConstraint = 1 << 5, // Reverse inference for mapped type
58665866
ContravariantConditional = 1 << 6, // Conditional type in contravariant position
58675867
ReturnType = 1 << 7, // Inference made from return type of generic function
5868-
LiteralKeyof = 1 << 8, // Inference made from a string literal to a keyof T
5869-
NoConstraints = 1 << 9, // Don't infer from constraints of instantiable types
5870-
AlwaysStrict = 1 << 10, // Always use strict rules for contravariant inferences
5871-
MaxValue = 1 << 11, // Seed for inference priority tracking
5868+
BindingPattern = 1 << 8, // Inference made from binding pattern
5869+
LiteralKeyof = 1 << 9, // Inference made from a string literal to a keyof T
5870+
NoConstraints = 1 << 10, // Don't infer from constraints of instantiable types
5871+
AlwaysStrict = 1 << 11, // Always use strict rules for contravariant inferences
5872+
MaxValue = 1 << 12, // Seed for inference priority tracking
58725873

58735874
PriorityImpliesCombination = ReturnType | MappedTypeConstraint | LiteralKeyof, // These priorities imply that the resulting type should be a combination of all candidates
58745875
Circularity = -1, // Inference circularity (value less than all other priorities)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
declare function f2<T>(cb: () => T): T;
2+
const [e1, e2, e3] = f2(() => [1, "hi", true]);
3+
4+
declare function f1<T>(): T;
5+
const {} = f1(); // error
6+
const { p1 } = f1(); // error
7+
8+
declare function pick<O, T extends keyof O>(keys: T[], obj?: O): Pick<O, T>;
9+
const _ = pick(['b'], { a: 'a', b: 'b' }); // T: "b"
10+
const { } = pick(['b'], { a: 'a', b: 'b' }); // T: "b" | "a" ???
11+
12+
type Dispatch<A = { type: any; [extraProps: string]: any }> = { <T extends A>(action: T): T };
13+
type IFuncs = { readonly [key: string]: (...p: any) => void };
14+
type IDestructuring<T extends IFuncs> = { readonly [key in keyof T]?: (...p: Parameters<T[key]>) => void };
15+
type Destructuring<T extends IFuncs, U extends IDestructuring<T>> = (dispatch: Dispatch<any>, funcs: T) => U;
16+
const funcs1 = {
17+
funcA: (a: boolean): void => {},
18+
funcB: (b: string, bb: string): void => {},
19+
funcC: (c: number, cc: number, ccc: boolean): void => {},
20+
};
21+
type TFuncs1 = typeof funcs1;
22+
declare function useReduxDispatch1<T extends IDestructuring<TFuncs1>>(destructuring: Destructuring<TFuncs1, T>): T;
23+
const {} = useReduxDispatch1(
24+
(d, f) => ({
25+
funcA: (...p) => d(f.funcA(...p)),
26+
funcB: (...p) => d(f.funcB(...p)),
27+
funcC: (...p) => d(f.funcC(...p))
28+
})
29+
);

0 commit comments

Comments
 (0)