-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Improve inference for context sensitive functions within reverse mapped types #54029
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
Changes from 7 commits
e90edb3
557cd99
4774f8f
b7eae05
a0804b5
57b54c9
fae5ae6
34d675a
a8e8a24
d71dcd2
5b33846
cca600f
e7e9125
5086dfa
b5c6ef4
9e748b7
f38ceb3
2724523
ec14355
83b0614
7291707
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 |
|---|---|---|
|
|
@@ -7539,13 +7539,14 @@ export function getCheckFlags(symbol: Symbol): CheckFlags { | |
|
|
||
| /** @internal */ | ||
| export function getDeclarationModifierFlagsFromSymbol(s: Symbol, isWrite = false): ModifierFlags { | ||
| if (s.valueDeclaration) { | ||
| const checkFlags = getCheckFlags(s); | ||
| if (!(checkFlags & CheckFlags.ReverseMapped) && s.valueDeclaration) { | ||
|
Contributor
Author
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. Since I added
Contributor
Author
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. Basically, this change just maintains compatibility with the old behavior as |
||
| const declaration = (isWrite && s.declarations && find(s.declarations, isSetAccessorDeclaration)) | ||
| || (s.flags & SymbolFlags.GetAccessor && find(s.declarations, isGetAccessorDeclaration)) || s.valueDeclaration; | ||
| const flags = getCombinedModifierFlags(declaration); | ||
| return s.parent && s.parent.flags & SymbolFlags.Class ? flags : flags & ~ModifierFlags.AccessibilityModifier; | ||
| } | ||
| if (getCheckFlags(s) & CheckFlags.Synthetic) { | ||
| if (checkFlags & CheckFlags.Synthetic) { | ||
| // NOTE: potentially unchecked cast to TransientSymbol | ||
| const checkFlags = (s as TransientSymbol).links.checkFlags; | ||
| const accessModifier = checkFlags & CheckFlags.ContainsPrivate ? ModifierFlags.Private : | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,168 @@ | ||
| tests/cases/conformance/types/typeRelationships/typeInference/intraExpressionInferencesReverseMappedTypes.ts(67,21): error TS18046: 'x' is of type 'unknown'. | ||
| tests/cases/conformance/types/typeRelationships/typeInference/intraExpressionInferencesReverseMappedTypes.ts(71,21): error TS18046: 'x' is of type 'unknown'. | ||
| tests/cases/conformance/types/typeRelationships/typeInference/intraExpressionInferencesReverseMappedTypes.ts(80,21): error TS18046: 'x' is of type 'unknown'. | ||
| tests/cases/conformance/types/typeRelationships/typeInference/intraExpressionInferencesReverseMappedTypes.ts(86,21): error TS18046: 'x' is of type 'unknown'. | ||
| tests/cases/conformance/types/typeRelationships/typeInference/intraExpressionInferencesReverseMappedTypes.ts(95,21): error TS18046: 'x' is of type 'unknown'. | ||
| tests/cases/conformance/types/typeRelationships/typeInference/intraExpressionInferencesReverseMappedTypes.ts(101,21): error TS18046: 'x' is of type 'unknown'. | ||
|
Contributor
Author
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. All of those relate to the tuple-based tests that I added and those are not expected. It doesn't work because in tuples both With objects I could try to fix this in this PR but I also feel like this would require changes that could be moved to a separate followup PR. This PR could focus on the base mechanism for this improvement and on object-based cases. |
||
|
|
||
|
|
||
| ==== tests/cases/conformance/types/typeRelationships/typeInference/intraExpressionInferencesReverseMappedTypes.ts (6 errors) ==== | ||
| // repro cases based on https://github.com/microsoft/TypeScript/issues/53018 | ||
|
|
||
| declare function f<T>( | ||
| arg: { | ||
| [K in keyof T]: { | ||
| produce: (n: string) => T[K]; | ||
| consume: (x: T[K]) => void; | ||
| }; | ||
| } | ||
| ): T; | ||
|
|
||
| const res1 = f({ | ||
| a: { | ||
| produce: (n) => n, | ||
| consume: (x) => x.toLowerCase(), | ||
| }, | ||
| b: { | ||
| produce: (n) => ({ v: n }), | ||
| consume: (x) => x.v.toLowerCase(), | ||
| }, | ||
| }); | ||
|
|
||
| const res2 = f({ | ||
| a: { | ||
| produce: function () { | ||
| return "hello"; | ||
| }, | ||
| consume: (x) => x.toLowerCase(), | ||
| }, | ||
| b: { | ||
| produce: function () { | ||
| return { v: "hello" }; | ||
| }, | ||
| consume: (x) => x.v.toLowerCase(), | ||
| }, | ||
| }); | ||
|
|
||
| const res3 = f({ | ||
| a: { | ||
| produce() { | ||
| return "hello"; | ||
| }, | ||
| consume: (x) => x.toLowerCase(), | ||
| }, | ||
| b: { | ||
| produce() { | ||
| return { v: "hello" }; | ||
| }, | ||
| consume: (x) => x.v.toLowerCase(), | ||
| }, | ||
| }); | ||
|
|
||
| declare function f2<T extends unknown[]>( | ||
| arg: [ | ||
| ...{ | ||
| [K in keyof T]: { | ||
| produce: (n: string) => T[K]; | ||
| consume: (x: T[K]) => void; | ||
| }; | ||
| } | ||
| ] | ||
| ): T; | ||
|
|
||
| const res4 = f2([ | ||
| { | ||
| produce: (n) => n, | ||
| consume: (x) => x.toLowerCase(), | ||
| ~ | ||
| !!! error TS18046: 'x' is of type 'unknown'. | ||
| }, | ||
| { | ||
| produce: (n) => ({ v: n }), | ||
| consume: (x) => x.v.toLowerCase(), | ||
| ~ | ||
| !!! error TS18046: 'x' is of type 'unknown'. | ||
| }, | ||
| ]); | ||
|
|
||
| const res5 = f2([ | ||
| { | ||
| produce: function () { | ||
| return "hello"; | ||
| }, | ||
| consume: (x) => x.toLowerCase(), | ||
| ~ | ||
| !!! error TS18046: 'x' is of type 'unknown'. | ||
| }, | ||
| { | ||
| produce: function () { | ||
| return { v: "hello" }; | ||
| }, | ||
| consume: (x) => x.v.toLowerCase(), | ||
| ~ | ||
| !!! error TS18046: 'x' is of type 'unknown'. | ||
| }, | ||
| ]); | ||
|
|
||
| const res6 = f2([ | ||
| { | ||
| produce() { | ||
| return "hello"; | ||
| }, | ||
| consume: (x) => x.toLowerCase(), | ||
| ~ | ||
| !!! error TS18046: 'x' is of type 'unknown'. | ||
| }, | ||
| { | ||
| produce() { | ||
| return { v: "hello" }; | ||
| }, | ||
| consume: (x) => x.v.toLowerCase(), | ||
| ~ | ||
| !!! error TS18046: 'x' is of type 'unknown'. | ||
| }, | ||
| ]); | ||
|
|
||
| declare function f3<T>( | ||
| arg: { | ||
| [K in keyof T]: { | ||
| other: number, | ||
| produce: (n: string) => T[K]; | ||
| consume: (x: T[K]) => void; | ||
| }; | ||
| } | ||
| ): T; | ||
|
|
||
| const res7 = f3({ | ||
| a: { | ||
| other: 42, | ||
| produce: (n) => n, | ||
| consume: (x) => x.toLowerCase(), | ||
| }, | ||
| b: { | ||
| other: 100, | ||
| produce: (n) => ({ v: n }), | ||
| consume: (x) => x.v.toLowerCase(), | ||
| }, | ||
| }); | ||
|
|
||
| declare function f4<T>( | ||
| arg: { | ||
| [K in keyof T]: [ | ||
| (n: string) => T[K], | ||
| (x: T[K]) => void | ||
| ]; | ||
| } | ||
| ): T; | ||
|
|
||
| const res8 = f4({ | ||
| a: [ | ||
| (n) => n, | ||
| (x) => x.toLowerCase(), | ||
| ], | ||
| b: [ | ||
| (n) => ({ v: n }), | ||
| (x) => x.v.toLowerCase(), | ||
| ], | ||
| }); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.