New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Include type parameter defaults in contextual typing #50994
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27534,7 +27534,7 @@ namespace ts { | |
const inferenceContext = getInferenceContext(node); | ||
// If no inferences have been made, nothing is gained from instantiating as type parameters | ||
// would just be replaced with their defaults similar to the apparent type. | ||
if (inferenceContext && contextFlags! & ContextFlags.Signature && some(inferenceContext.inferences, hasInferenceCandidates)) { | ||
if (inferenceContext && contextFlags! & ContextFlags.Signature && some(inferenceContext.inferences, hasInferenceCandidatesOrDefault)) { | ||
// For contextual signatures we incorporate all inferences made so far, e.g. from return | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I also have an additional fix touching this very line. Since this is being touched now, perhaps you could take a look if it looks any good? :p There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not quite sure what that fix is trying to accomplish. Either way I don't think it is related to the issue being solved in this PR, so I think it's better to keep it separate. |
||
// types as well as arguments to the left in a function call. | ||
return instantiateInstantiableTypes(contextualType, inferenceContext.nonFixingMapper); | ||
|
@@ -35145,6 +35145,10 @@ namespace ts { | |
return !!(info.candidates || info.contraCandidates); | ||
} | ||
|
||
function hasInferenceCandidatesOrDefault(info: InferenceInfo) { | ||
return !!(info.candidates || info.contraCandidates || hasTypeParameterDefault(info.typeParameter)); | ||
} | ||
|
||
function hasOverlappingInferences(a: InferenceInfo[], b: InferenceInfo[]) { | ||
for (let i = 0; i < a.length; i++) { | ||
if (hasInferenceCandidates(a[i]) && hasInferenceCandidates(b[i])) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
//// [genericInferenceDefaultTypeParameter.ts] | ||
// Repro from #50858 | ||
|
||
type Type = { | ||
a: (e: string) => void; | ||
b: (e: number) => void; | ||
} | ||
|
||
declare function f1<T extends keyof Type = "a">(props: Type[T]): void; | ||
|
||
f1(event => { }); | ||
f1<"a">(event => { }); | ||
f1<"b">(event => { }); | ||
|
||
|
||
//// [genericInferenceDefaultTypeParameter.js] | ||
"use strict"; | ||
// Repro from #50858 | ||
f1(function (event) { }); | ||
f1(function (event) { }); | ||
f1(function (event) { }); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
=== tests/cases/compiler/genericInferenceDefaultTypeParameter.ts === | ||
// Repro from #50858 | ||
|
||
type Type = { | ||
>Type : Symbol(Type, Decl(genericInferenceDefaultTypeParameter.ts, 0, 0)) | ||
|
||
a: (e: string) => void; | ||
>a : Symbol(a, Decl(genericInferenceDefaultTypeParameter.ts, 2, 13)) | ||
>e : Symbol(e, Decl(genericInferenceDefaultTypeParameter.ts, 3, 8)) | ||
|
||
b: (e: number) => void; | ||
>b : Symbol(b, Decl(genericInferenceDefaultTypeParameter.ts, 3, 27)) | ||
>e : Symbol(e, Decl(genericInferenceDefaultTypeParameter.ts, 4, 8)) | ||
} | ||
|
||
declare function f1<T extends keyof Type = "a">(props: Type[T]): void; | ||
>f1 : Symbol(f1, Decl(genericInferenceDefaultTypeParameter.ts, 5, 1)) | ||
>T : Symbol(T, Decl(genericInferenceDefaultTypeParameter.ts, 7, 20)) | ||
>Type : Symbol(Type, Decl(genericInferenceDefaultTypeParameter.ts, 0, 0)) | ||
>props : Symbol(props, Decl(genericInferenceDefaultTypeParameter.ts, 7, 48)) | ||
>Type : Symbol(Type, Decl(genericInferenceDefaultTypeParameter.ts, 0, 0)) | ||
>T : Symbol(T, Decl(genericInferenceDefaultTypeParameter.ts, 7, 20)) | ||
|
||
f1(event => { }); | ||
>f1 : Symbol(f1, Decl(genericInferenceDefaultTypeParameter.ts, 5, 1)) | ||
>event : Symbol(event, Decl(genericInferenceDefaultTypeParameter.ts, 9, 3)) | ||
|
||
f1<"a">(event => { }); | ||
>f1 : Symbol(f1, Decl(genericInferenceDefaultTypeParameter.ts, 5, 1)) | ||
>event : Symbol(event, Decl(genericInferenceDefaultTypeParameter.ts, 10, 8)) | ||
|
||
f1<"b">(event => { }); | ||
>f1 : Symbol(f1, Decl(genericInferenceDefaultTypeParameter.ts, 5, 1)) | ||
>event : Symbol(event, Decl(genericInferenceDefaultTypeParameter.ts, 11, 8)) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
=== tests/cases/compiler/genericInferenceDefaultTypeParameter.ts === | ||
// Repro from #50858 | ||
|
||
type Type = { | ||
>Type : { a: (e: string) => void; b: (e: number) => void; } | ||
|
||
a: (e: string) => void; | ||
>a : (e: string) => void | ||
>e : string | ||
|
||
b: (e: number) => void; | ||
>b : (e: number) => void | ||
>e : number | ||
} | ||
|
||
declare function f1<T extends keyof Type = "a">(props: Type[T]): void; | ||
>f1 : <T extends keyof Type = "a">(props: Type[T]) => void | ||
>props : Type[T] | ||
|
||
f1(event => { }); | ||
>f1(event => { }) : void | ||
>f1 : <T extends keyof Type = "a">(props: Type[T]) => void | ||
>event => { } : (event: string) => void | ||
>event : string | ||
|
||
f1<"a">(event => { }); | ||
>f1<"a">(event => { }) : void | ||
>f1 : <T extends keyof Type = "a">(props: Type[T]) => void | ||
>event => { } : (event: string) => void | ||
>event : string | ||
|
||
f1<"b">(event => { }); | ||
>f1<"b">(event => { }) : void | ||
>f1 : <T extends keyof Type = "a">(props: Type[T]) => void | ||
>event => { } : (event: number) => void | ||
>event : number | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
//// [genericInferenceDefaultTypeParameterJsxReact.tsx] | ||
/// <reference path="/.lib/react16.d.ts" /> | ||
|
||
// Repro from #50858 | ||
|
||
import React, { ComponentPropsWithRef, ElementType, ReactNode } from 'react'; | ||
|
||
type ButtonBaseProps<T extends ElementType> = ComponentPropsWithRef<T> & { children?: ReactNode }; | ||
|
||
function Component<T extends ElementType = 'span'>(props: ButtonBaseProps<T>) { | ||
return <></>; | ||
} | ||
|
||
const v1 = <Component onClick={e => e.preventDefault()} />; | ||
|
||
|
||
//// [genericInferenceDefaultTypeParameterJsxReact.js] | ||
"use strict"; | ||
/// <reference path="react16.d.ts" /> | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
exports.__esModule = true; | ||
// Repro from #50858 | ||
var react_1 = __importDefault(require("react")); | ||
function Component(props) { | ||
return react_1["default"].createElement(react_1["default"].Fragment, null); | ||
} | ||
var v1 = react_1["default"].createElement(Component, { onClick: function (e) { return e.preventDefault(); } }); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
=== tests/cases/compiler/genericInferenceDefaultTypeParameterJsxReact.tsx === | ||
/// <reference path="react16.d.ts" /> | ||
|
||
// Repro from #50858 | ||
|
||
import React, { ComponentPropsWithRef, ElementType, ReactNode } from 'react'; | ||
>React : Symbol(React, Decl(genericInferenceDefaultTypeParameterJsxReact.tsx, 4, 6)) | ||
>ComponentPropsWithRef : Symbol(ComponentPropsWithRef, Decl(genericInferenceDefaultTypeParameterJsxReact.tsx, 4, 15)) | ||
>ElementType : Symbol(ElementType, Decl(genericInferenceDefaultTypeParameterJsxReact.tsx, 4, 38)) | ||
>ReactNode : Symbol(ReactNode, Decl(genericInferenceDefaultTypeParameterJsxReact.tsx, 4, 51)) | ||
|
||
type ButtonBaseProps<T extends ElementType> = ComponentPropsWithRef<T> & { children?: ReactNode }; | ||
>ButtonBaseProps : Symbol(ButtonBaseProps, Decl(genericInferenceDefaultTypeParameterJsxReact.tsx, 4, 77)) | ||
>T : Symbol(T, Decl(genericInferenceDefaultTypeParameterJsxReact.tsx, 6, 21)) | ||
>ElementType : Symbol(ElementType, Decl(genericInferenceDefaultTypeParameterJsxReact.tsx, 4, 38)) | ||
>ComponentPropsWithRef : Symbol(ComponentPropsWithRef, Decl(genericInferenceDefaultTypeParameterJsxReact.tsx, 4, 15)) | ||
>T : Symbol(T, Decl(genericInferenceDefaultTypeParameterJsxReact.tsx, 6, 21)) | ||
>children : Symbol(children, Decl(genericInferenceDefaultTypeParameterJsxReact.tsx, 6, 74)) | ||
>ReactNode : Symbol(ReactNode, Decl(genericInferenceDefaultTypeParameterJsxReact.tsx, 4, 51)) | ||
|
||
function Component<T extends ElementType = 'span'>(props: ButtonBaseProps<T>) { | ||
>Component : Symbol(Component, Decl(genericInferenceDefaultTypeParameterJsxReact.tsx, 6, 98)) | ||
>T : Symbol(T, Decl(genericInferenceDefaultTypeParameterJsxReact.tsx, 8, 19)) | ||
>ElementType : Symbol(ElementType, Decl(genericInferenceDefaultTypeParameterJsxReact.tsx, 4, 38)) | ||
>props : Symbol(props, Decl(genericInferenceDefaultTypeParameterJsxReact.tsx, 8, 51)) | ||
>ButtonBaseProps : Symbol(ButtonBaseProps, Decl(genericInferenceDefaultTypeParameterJsxReact.tsx, 4, 77)) | ||
>T : Symbol(T, Decl(genericInferenceDefaultTypeParameterJsxReact.tsx, 8, 19)) | ||
|
||
return <></>; | ||
} | ||
|
||
const v1 = <Component onClick={e => e.preventDefault()} />; | ||
>v1 : Symbol(v1, Decl(genericInferenceDefaultTypeParameterJsxReact.tsx, 12, 5)) | ||
>Component : Symbol(Component, Decl(genericInferenceDefaultTypeParameterJsxReact.tsx, 6, 98)) | ||
>onClick : Symbol(onClick, Decl(genericInferenceDefaultTypeParameterJsxReact.tsx, 12, 21)) | ||
>e : Symbol(e, Decl(genericInferenceDefaultTypeParameterJsxReact.tsx, 12, 31)) | ||
>e.preventDefault : Symbol(React.SyntheticEvent.preventDefault, Decl(react16.d.ts, 642, 31)) | ||
>e : Symbol(e, Decl(genericInferenceDefaultTypeParameterJsxReact.tsx, 12, 31)) | ||
>preventDefault : Symbol(React.SyntheticEvent.preventDefault, Decl(react16.d.ts, 642, 31)) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
=== tests/cases/compiler/genericInferenceDefaultTypeParameterJsxReact.tsx === | ||
/// <reference path="react16.d.ts" /> | ||
|
||
// Repro from #50858 | ||
|
||
import React, { ComponentPropsWithRef, ElementType, ReactNode } from 'react'; | ||
>React : typeof React | ||
>ComponentPropsWithRef : any | ||
>ElementType : any | ||
>ReactNode : any | ||
|
||
type ButtonBaseProps<T extends ElementType> = ComponentPropsWithRef<T> & { children?: ReactNode }; | ||
>ButtonBaseProps : ButtonBaseProps<T> | ||
>children : React.ReactNode | ||
|
||
function Component<T extends ElementType = 'span'>(props: ButtonBaseProps<T>) { | ||
>Component : <T extends React.ElementType<any> = "span">(props: ButtonBaseProps<T>) => JSX.Element | ||
>props : ButtonBaseProps<T> | ||
|
||
return <></>; | ||
><></> : JSX.Element | ||
} | ||
|
||
const v1 = <Component onClick={e => e.preventDefault()} />; | ||
>v1 : JSX.Element | ||
><Component onClick={e => e.preventDefault()} /> : JSX.Element | ||
>Component : <T extends React.ElementType<any> = "span">(props: ButtonBaseProps<T>) => JSX.Element | ||
>onClick : (e: React.MouseEvent<HTMLSpanElement>) => void | ||
>e => e.preventDefault() : (e: React.MouseEvent<HTMLSpanElement>) => void | ||
>e : React.MouseEvent<HTMLSpanElement> | ||
>e.preventDefault() : void | ||
>e.preventDefault : () => void | ||
>e : React.MouseEvent<HTMLSpanElement> | ||
>preventDefault : () => void | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// @strict: true | ||
|
||
// Repro from #50858 | ||
|
||
type Type = { | ||
a: (e: string) => void; | ||
b: (e: number) => void; | ||
} | ||
|
||
declare function f1<T extends keyof Type = "a">(props: Type[T]): void; | ||
|
||
f1(event => { }); | ||
f1<"a">(event => { }); | ||
f1<"b">(event => { }); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// @strict: true | ||
// @esModuleInterop: true | ||
// @jsx: react | ||
|
||
/// <reference path="/.lib/react16.d.ts" /> | ||
|
||
// Repro from #50858 | ||
|
||
import React, { ComponentPropsWithRef, ElementType, ReactNode } from 'react'; | ||
|
||
type ButtonBaseProps<T extends ElementType> = ComponentPropsWithRef<T> & { children?: ReactNode }; | ||
|
||
function Component<T extends ElementType = 'span'>(props: ButtonBaseProps<T>) { | ||
return <></>; | ||
} | ||
|
||
const v1 = <Component onClick={e => e.preventDefault()} />; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this part of the comment here still relevant? with the code change in this PR this now reads weirdly to me, or there is some additional context missing here - like what kind of default type parameters should be ignored and what kind of default parameters might be useful. Or perhaps this comment was never about defaults and it should mention base constraints?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, that should say constraints, not defaults.