Skip to content

Combine multiple overloads into a single contextual signature - #42620

Merged
Wesley Wigham (weswigham) merged 7 commits into
microsoft:masterfrom
weswigham:no-implicit-any-overloaded-contextual-signatures
Feb 22, 2021
Merged

Combine multiple overloads into a single contextual signature#42620
Wesley Wigham (weswigham) merged 7 commits into
microsoft:masterfrom
weswigham:no-implicit-any-overloaded-contextual-signatures

Conversation

@weswigham

Copy link
Copy Markdown
Member

With this PR, we combine multiple overloads into a single contextual signature when noImplcitAny is set (for backwards compatibility, since otherwise these positions had type any). The rules for signature combining are similar to union signature combining, but swapping union/intersection rules where applicable; Either no generics, or identical generic lists, Parameters (and this parameters) union together, return types (and predicates) intersect (return types/predicates are likely visible via return type inference, so do need sensible rules).

With the caveat that this only changes our behavior when noImplicitAny is set, this:
Fixes#42559
Fixes#42504
Doesn't change #38625 - since the signatures in question have a mix of type parameters and no type parameters.
Doesn't change #35641 - there's no contextual typing involved; generic signature resolution has a similar drawback where it doesn't handle overloads which this PR does not touch.
Fixesthis comment though not the containing issue (which is moreso a dupe/precursor of #35641)

@weswigham

Copy link
Copy Markdown
MemberAuthor

@typescript-bot

TypeScript Bot (typescript-bot) commented Feb 2, 2021

Copy link
Copy Markdown
Contributor

Heya Wesley Wigham (@weswigham), I've started to run the parallelized community code test suite on this PR at 429b88f. You can monitor the build here.

@typescript-bot

TypeScript Bot (typescript-bot) commented Feb 2, 2021

Copy link
Copy Markdown
Contributor

Heya Wesley Wigham (@weswigham), I've started to run the parallelized Definitely Typed test suite on this PR at 429b88f. You can monitor the build here.

@typescript-bot

TypeScript Bot (typescript-bot) commented Feb 2, 2021

Copy link
Copy Markdown
Contributor

Heya Wesley Wigham (@weswigham), I've started to run the extended test suite on this PR at 429b88f. You can monitor the build here.

@typescript-bot

TypeScript Bot (typescript-bot) commented Feb 2, 2021

Copy link
Copy Markdown
Contributor

Heya Wesley Wigham (@weswigham), I've started to run the perf test suite on this PR at 429b88f. You can monitor the build here.

Update: The results are in!

@typescript-bot

Copy link
Copy Markdown
Contributor

Wesley Wigham (@weswigham)
The results of the perf run you requested are in!

Here they are:

Comparison Report - master..42620

Metricmaster42620DeltaBestWorst
Angular - node (v10.16.3, x64)
Memory used346,406k (± 0.03%)346,444k (± 0.02%)+38k (+ 0.01%)346,262k346,645k
Parse Time1.92s (± 0.55%)1.91s (± 0.55%)-0.01s (- 0.52%)1.89s1.93s
Bind Time0.82s (± 0.73%)0.82s (± 0.60%)-0.00s (- 0.12%)0.81s0.83s
Check Time5.01s (± 0.59%)4.97s (± 0.47%)-0.04s (- 0.74%)4.93s5.02s
Emit Time5.27s (± 0.82%)5.24s (± 0.66%)-0.03s (- 0.57%)5.18s5.32s
Total Time13.03s (± 0.43%)12.96s (± 0.40%)-0.08s (- 0.58%)12.86s13.07s
Compiler-Unions - node (v10.16.3, x64)
Memory used214,972k (± 0.02%)214,953k (± 0.04%)-20k (- 0.01%)214,734k215,092k
Parse Time0.78s (± 0.63%)0.77s (± 0.91%)-0.01s (- 0.64%)0.76s0.79s
Bind Time0.50s (± 0.75%)0.49s (± 1.01%)-0.00s (- 0.00%)0.48s0.50s
Check Time10.72s (± 0.84%)10.70s (± 0.40%)-0.02s (- 0.18%)10.62s10.79s
Emit Time2.37s (± 1.51%)2.33s (± 1.24%)-0.04s (- 1.77%)2.28s2.40s
Total Time14.35s (± 0.73%)14.29s (± 0.33%)-0.06s (- 0.42%)14.18s14.39s
Monaco - node (v10.16.3, x64)
Memory used355,237k (± 0.04%)355,331k (± 0.03%)+94k (+ 0.03%)355,149k355,586k
Parse Time1.55s (± 0.71%)1.55s (± 0.40%)+0.00s (+ 0.19%)1.54s1.56s
Bind Time0.73s (± 0.65%)0.73s (± 0.65%)-0.00s (- 0.00%)0.72s0.74s
Check Time5.12s (± 0.58%)5.14s (± 0.47%)+0.02s (+ 0.41%)5.07s5.19s
Emit Time2.79s (± 0.67%)2.78s (± 0.54%)-0.01s (- 0.36%)2.75s2.83s
Total Time10.18s (± 0.53%)10.19s (± 0.30%)+0.01s (+ 0.15%)10.10s10.25s
TFS - node (v10.16.3, x64)
Memory used308,160k (± 0.02%)308,198k (± 0.02%)+38k (+ 0.01%)308,102k308,311k
Parse Time1.20s (± 0.46%)1.20s (± 0.69%)+0.00s (+ 0.17%)1.19s1.22s
Bind Time0.68s (± 0.59%)0.68s (± 0.95%)+0.00s (+ 0.44%)0.67s0.70s
Check Time4.59s (± 0.51%)4.60s (± 0.57%)+0.02s (+ 0.33%)4.54s4.67s
Emit Time2.91s (± 0.46%)2.92s (± 0.91%)+0.01s (+ 0.31%)2.85s3.00s
Total Time9.38s (± 0.33%)9.41s (± 0.56%)+0.03s (+ 0.32%)9.26s9.55s
material-ui - node (v10.16.3, x64)
Memory used496,311k (± 0.01%)496,227k (± 0.01%)-84k (- 0.02%)496,125k496,390k
Parse Time1.98s (± 0.82%)1.97s (± 0.44%)-0.01s (- 0.55%)1.95s1.99s
Bind Time0.65s (± 0.80%)0.65s (± 0.68%)+0.00s (+ 0.15%)0.64s0.66s
Check Time13.98s (± 0.46%)13.95s (± 0.34%)-0.04s (- 0.26%)13.82s14.04s
Emit Time0.00s (± 0.00%)0.00s (± 0.00%)0.00s ( NaN%)0.00s0.00s
Total Time16.62s (± 0.45%)16.57s (± 0.32%)-0.05s (- 0.29%)16.42s16.67s
Angular - node (v12.1.0, x64)
Memory used323,732k (± 0.11%)324,112k (± 0.02%)+380k (+ 0.12%)323,980k324,318k
Parse Time1.90s (± 0.59%)1.90s (± 0.39%)+0.00s (+ 0.21%)1.88s1.92s
Bind Time0.80s (± 0.72%)0.80s (± 1.02%)+0.00s (+ 0.00%)0.78s0.82s
Check Time4.91s (± 1.12%)4.89s (± 0.43%)-0.02s (- 0.35%)4.84s4.94s
Emit Time5.45s (± 2.07%)5.39s (± 0.62%)-0.06s (- 1.05%)5.33s5.48s
Total Time13.05s (± 1.06%)12.98s (± 0.31%)-0.07s (- 0.55%)12.89s13.06s
Compiler-Unions - node (v12.1.0, x64)
Memory used200,361k (± 0.06%)200,345k (± 0.07%)-16k (- 0.01%)200,054k200,592k
Parse Time0.76s (± 0.85%)0.77s (± 0.44%)+0.00s (+ 0.66%)0.76s0.77s
Bind Time0.50s (± 0.89%)0.50s (± 0.80%)+0.00s (+ 0.20%)0.49s0.51s
Check Time9.78s (± 0.77%)9.82s (± 0.62%)+0.04s (+ 0.37%)9.73s9.95s
Emit Time2.32s (± 1.48%)2.36s (± 1.90%)+0.04s (+ 1.55%)2.29s2.47s
Total Time13.36s (± 0.69%)13.44s (± 0.46%)+0.08s (+ 0.60%)13.30s13.56s
Monaco - node (v12.1.0, x64)
Memory used337,549k (± 0.02%)337,509k (± 0.02%)-40k (- 0.01%)337,334k337,699k
Parse Time1.53s (± 0.71%)1.53s (± 0.53%)+0.01s (+ 0.33%)1.52s1.56s
Bind Time0.70s (± 1.06%)0.70s (± 0.67%)-0.00s (- 0.43%)0.69s0.71s
Check Time4.91s (± 0.49%)4.94s (± 0.42%)+0.03s (+ 0.57%)4.90s4.99s
Emit Time2.84s (± 0.65%)2.84s (± 0.66%)+0.00s (+ 0.11%)2.81s2.89s
Total Time9.97s (± 0.39%)10.01s (± 0.43%)+0.04s (+ 0.40%)9.95s10.14s
TFS - node (v12.1.0, x64)
Memory used292,428k (± 0.03%)292,385k (± 0.03%)-43k (- 0.01%)292,194k292,546k
Parse Time1.22s (± 0.41%)1.22s (± 0.57%)+0.00s (+ 0.33%)1.20s1.23s
Bind Time0.65s (± 0.85%)0.66s (± 0.76%)+0.00s (+ 0.46%)0.64s0.66s
Check Time4.50s (± 0.44%)4.50s (± 0.48%)+0.00s (+ 0.09%)4.46s4.55s
Emit Time2.92s (± 0.55%)2.94s (± 0.96%)+0.01s (+ 0.48%)2.86s3.00s
Total Time9.29s (± 0.32%)9.31s (± 0.46%)+0.02s (+ 0.27%)9.19s9.41s
material-ui - node (v12.1.0, x64)
Memory used473,379k (± 0.06%)473,482k (± 0.01%)+103k (+ 0.02%)473,400k473,633k
Parse Time1.99s (± 0.62%)1.99s (± 0.42%)-0.00s (- 0.05%)1.97s2.01s
Bind Time0.64s (± 0.62%)0.64s (± 0.46%)+0.00s (+ 0.16%)0.64s0.65s
Check Time12.54s (± 0.67%)12.55s (± 0.51%)+0.01s (+ 0.06%)12.42s12.77s
Emit Time0.00s (± 0.00%)0.00s (± 0.00%)0.00s ( NaN%)0.00s0.00s
Total Time15.18s (± 0.56%)15.19s (± 0.45%)+0.01s (+ 0.06%)15.04s15.41s
Angular - node (v14.15.1, x64)
Memory used322,620k (± 0.01%)322,669k (± 0.01%)+49k (+ 0.02%)322,564k322,703k
Parse Time1.91s (± 0.43%)1.91s (± 0.52%)-0.00s (- 0.05%)1.89s1.94s
Bind Time0.85s (± 0.82%)0.85s (± 1.07%)0.00s ( 0.00%)0.84s0.88s
Check Time4.89s (± 0.34%)4.90s (± 0.31%)+0.01s (+ 0.20%)4.87s4.93s
Emit Time5.47s (± 0.20%)5.48s (± 0.73%)+0.01s (+ 0.16%)5.41s5.61s
Total Time13.12s (± 0.16%)13.14s (± 0.40%)+0.02s (+ 0.14%)13.06s13.29s
Compiler-Unions - node (v14.15.1, x64)
Memory used201,184k (± 0.55%)200,816k (± 0.50%)-367k (- 0.18%)199,630k203,457k
Parse Time0.80s (± 0.56%)0.79s (± 0.46%)-0.00s (- 0.50%)0.79s0.80s
Bind Time0.53s (± 0.42%)0.53s (± 0.00%)+0.00s (+ 0.19%)0.53s0.53s
Check Time9.85s (± 1.24%)9.81s (± 0.74%)-0.05s (- 0.47%)9.63s9.93s
Emit Time2.34s (± 0.90%)2.33s (± 0.97%)-0.01s (- 0.38%)2.31s2.40s
Total Time13.52s (± 0.93%)13.47s (± 0.68%)-0.05s (- 0.41%)13.26s13.65s
Monaco - node (v14.15.1, x64)
Memory used336,797k (± 0.01%)336,798k (± 0.01%)+1k (+ 0.00%)336,748k336,854k
Parse Time1.57s (± 0.53%)1.56s (± 0.60%)-0.01s (- 0.51%)1.54s1.58s
Bind Time0.73s (± 0.67%)0.74s (± 0.51%)+0.00s (+ 0.14%)0.73s0.74s
Check Time4.86s (± 0.42%)4.85s (± 0.28%)-0.00s (- 0.02%)4.83s4.89s
Emit Time2.90s (± 0.63%)2.90s (± 0.58%)+0.00s (+ 0.07%)2.86s2.95s
Total Time10.05s (± 0.25%)10.05s (± 0.26%)-0.01s (- 0.07%)9.98s10.11s
TFS - node (v14.15.1, x64)
Memory used291,551k (± 0.01%)291,593k (± 0.00%)+42k (+ 0.01%)291,566k291,615k
Parse Time1.26s (± 1.08%)1.24s (± 1.04%)-0.01s (- 1.03%)1.22s1.28s
Bind Time0.69s (± 1.08%)0.69s (± 0.87%)-0.00s (- 0.58%)0.67s0.70s
Check Time4.48s (± 0.44%)4.50s (± 0.52%)+0.02s (+ 0.54%)4.45s4.56s
Emit Time3.04s (± 0.59%)3.04s (± 0.67%)+0.01s (+ 0.23%)3.00s3.09s
Total Time9.46s (± 0.28%)9.48s (± 0.37%)+0.02s (+ 0.18%)9.39s9.55s
material-ui - node (v14.15.1, x64)
Memory used472,112k (± 0.06%)472,154k (± 0.06%)+42k (+ 0.01%)471,007k472,344k
Parse Time2.05s (± 0.56%)2.04s (± 0.63%)-0.01s (- 0.63%)2.01s2.06s
Bind Time0.69s (± 0.72%)0.70s (± 0.49%)+0.00s (+ 0.29%)0.69s0.70s
Check Time12.62s (± 0.66%)12.56s (± 0.42%)-0.06s (- 0.50%)12.43s12.69s
Emit Time0.00s (± 0.00%)0.00s (± 0.00%)0.00s ( NaN%)0.00s0.00s
Total Time15.37s (± 0.53%)15.29s (± 0.34%)-0.07s (- 0.48%)15.18s15.43s
System
Machine Namets-ci-ubuntu
Platformlinux 4.4.0-198-generic
Architecturex64
Available Memory16 GB
Available Memory8 GB
CPUs4 × Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz
Hosts
  • node (v10.16.3, x64)
  • node (v12.1.0, x64)
  • node (v14.15.1, x64)
Scenarios
  • Angular - node (v10.16.3, x64)
  • Angular - node (v12.1.0, x64)
  • Angular - node (v14.15.1, x64)
  • Compiler-Unions - node (v10.16.3, x64)
  • Compiler-Unions - node (v12.1.0, x64)
  • Compiler-Unions - node (v14.15.1, x64)
  • Monaco - node (v10.16.3, x64)
  • Monaco - node (v12.1.0, x64)
  • Monaco - node (v14.15.1, x64)
  • TFS - node (v10.16.3, x64)
  • TFS - node (v12.1.0, x64)
  • TFS - node (v14.15.1, x64)
  • material-ui - node (v10.16.3, x64)
  • material-ui - node (v12.1.0, x64)
  • material-ui - node (v14.15.1, x64)
BenchmarkNameIterations
Current4262010
Baselinemaster10

@typescript-bot

Copy link
Copy Markdown
Contributor

The user suite test run you requested has finished and failed. I've opened a PR with the baseline diff from master.

@weswigham

Wesley Wigham (weswigham) commented Feb 4, 2021

Copy link
Copy Markdown
MemberAuthor

Perf is good, rwc looks good (1 change removing an implicit any exactly where this should), user tests look clean, and DT brought up one change which is somewhat interesting - a function contextually typed by a type like:

((match: { x: string; }) => void) | { (form: "NFC" | "NFD" | "NFKC" | "NFKD"): string; (form?: string | undefined): string; } | undefined

previously, that 2-overload union member would produce no contextual information (since it had two overloads), making the 1-overload union the only union member with a visible contextual signature. Now, both union members produce a signature, they aren't identical, and the contextual signature is dropped entirely. I can preserve our current behavior here (dropping the two-overload's contextual information) without changing the behavior outside of union contextual types, but I'm unsure if we should? Certainly, we feel justified giving no contextual signature for

((match: { x: string; }) => void) | { (form: "NFC" | "NFD" | "NFKC" | "NFKD"): string; } | undefined

so why should the addition of an overload change that?

@weswigham

Copy link
Copy Markdown
MemberAuthor

TypeScript Bot (@typescript-bot) pack this

@typescript-bot

TypeScript Bot (typescript-bot) commented Feb 8, 2021

Copy link
Copy Markdown
Contributor

Heya Wesley Wigham (@weswigham), I've started to run the tarball bundle task on this PR at 33a5727. You can monitor the build here.

@typescript-bot

TypeScript Bot (typescript-bot) commented Feb 9, 2021

Copy link
Copy Markdown
Contributor

Hey Wesley Wigham (@weswigham), I've packed this into an installable tgz. You can install it for testing by referencing it in your package.json like so:

{
"devDependencies": {
"typescript": "https://typescript.visualstudio.com/cf7ac146-d525-443c-b23c-0d58337efebc/_apis/build/builds/95281/artifacts?artifactName=tgz&fileId=83BA68DE118EC9D31EF448A2AC81BDAA96BC0051E358379D9F308B08C0EF347902&fileName=/typescript-4.2.0-insiders.20210209.tgz"
}
}

and then running npm install.


There is also a playground for this build and an npm module you can use via "typescript": "npm:@typescript-deploys/pr-build@4.2.0-pr-42620-10".;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks pretty good. I have a couple of questions and a lot of minor style suggestions.

=== tests/cases/compiler/redefineArray.ts ===
Array = function (n:number, s:string) {return n;};
>Array = function (n:number, s:string) {return n;} : (n: number, s: string) => number
>Array = function (n:number, s:string) {return n;} : <T>(n: number, s: string) => number

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The addition of the type parameter seems a little odd. Why does a contextual signature give this function a type parameter?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Array's call signature has type parameters (and multiple overloads, hence why we only now pick it up), so our contextual signature logic says to persist those type parameters onto the inferred signature (so they can be inferred and used at the parameter types). That type parameter just happens to end up unused, since the parameters are all annotated with types that override the inferred ones. Specifically, it has the signatures:

 (arrayLength?: number): any[];
<T>(arrayLength: number): T[];
<T>(...items: T[]): T[];

so it used to be that you'd get no contextual signature whatsoever, whereas now the contextual signature is something like <T>(arrayLengthOrItem?: number | T, ...items: T[]): T[]. Technically any time a contextually typed signature has all the parameter types specified, we could probably omit these type parameters. Probably. You can see similar behavior in the types baselines today with only one overload and something like:

// @strictFunctionTypes: falseinterfaceMyCallable{<T>(a: T|number): T[];}constx: MyCallable=function(arg: number){returnnullasany};

(strictFunctionTypes has to be off for the assignment to succeed, in both cases). I don't know why, but we also only do this for function expressions and not arrow functions... that's probably indicative of some bug somewhere; but it's a preexisting one.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I figured it was pre-existing.

const obj: {field: Rule} = {
field: {
validate: (_t, _p, _s) => false,
normalize: match => match.x,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why doesn't this one get a contextual signature too?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a test capturing this change I describe from DT - that comment contains the explanation, and is the bulk of what I was trying to discuss at the design meeting.

}

function getUnionOrIntersectionType(types: Type[], kind: TypeFlags | undefined, unionReduction?: UnionReduction) {
return kind !== TypeFlags.Intersection ? getUnionType(types, unionReduction) : getIntersectionType(types);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this still correct? It's easier to read.

Suggested change
returnkind!==TypeFlags.Intersection ? getUnionType(types,unionReduction) : getIntersectionType(types);
returnkind===TypeFlags.Union ? getUnionType(types,unionReduction) : getIntersectionType(types);

@weswighamWesley Wigham (weswigham)Feb 9, 2021

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I intentionally made all the comparisons kind !== TypeFlags.Intersection so that the kind being undefined is synonymous with Union (to preserve the existing structure where there is no kind). Now, I don't intentionally leave kindundefined anywhere, but just in case, I've written the comparisons to be resilient to it (since it is an "optional" signature member, and maybe some plugin author manufactures signatures and send them into the checker, who knows).

Comment threadsrc/compiler/checker.ts Outdated
results.push(propType);
}
return getIntersectionType(results);
return getIntersectionType(results); // Same result for both union and intersection signatures

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why does this need to be commented? It didn't surprise me since no other code changed around here, so I think I'm missing the actual surprising thing.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The actual surprising thing is that nothing changed here. This code path handled union composite signatures... and now we're handling intersection composite signatures in the same way (rather than inverting anything), which is odd. The reason for that is explained in this comment (namely that for compat reasons we intentionally do "the wrong thing" for union signatures here, which happens to be "the right thing" for intersection signatures)

}
// A signature `this` type might be a read or a write position... It's very possible that it should be invariant
// and we should refuse to merge signatures if there are `this` types and they do not match. However, so as to be
// pessimistic when contextual typing, for now, we'll union the `this` types.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what would cause us to change this? (not a big fan of 'for now'-style comments because they don't have enough context with them)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also: this is basically a parameter, so it should union just like the other parameters.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so it should union just like the other parameters.

And so we are, the comment is just an inversion of the comment that already exists in combineUnionThisParam which does the opposite.

return params;
}

function combineSignaturesOfIntersectionMembers(left: Signature, right: Signature): Signature {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should probably come before combineIntersectionParameters and combineIntersectionThisParam

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is in the same order that the very similar combineUnionParameters and combineUnionThisParam are~

minArgCount,
(left.flags | right.flags) & SignatureFlags.PropagatingFlags
);
result.compositeKind = TypeFlags.Intersection;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stupid efficiency question: Is it more efficient to have createSignature set these? (I'm guessing not, since probably composite signatures (1) are rare (2) have their own internal class.)

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

createSignature sets them to undefined already, along with every other optional field on signatures~

Comment on lines +24958 to +24959
const longest = leftCount >= rightCount ? left : right;
const shorter = longest === left ? right : left;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could they be named longest/shortest or longer/shorter?

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This follows the same terminology we already use in combineUnionParameters, which combinedIntersectionParametersreally closely mirrors.

Comment on lines +24979 to +24982
const paramName = leftName === rightName ? leftName :
!leftName ? rightName :
!rightName ? leftName :
undefined;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uhhhhhhhhh, why not just leftName || rightName? I'm not even sure it's observable, but even if it is, some name is better than arg0.

@weswighamWesley Wigham (weswigham)Feb 9, 2021

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because that's what we merged for combineUnionParameters in #32056 :V

Also, "some name is better than arg0" isn't really true. Names carry semantic meaning, so let's say you have (index: number) => any and (object: Whatever): any - calling the result index where's it's type is number | Whatever has the potential to be misleading. Particularly problematic is when the types are the same, but semantically different, like
(length: number): any[] and (firstElement: number): any[] - yeah, number is the type of both, but there're not semantically the same! So calling both "length" or "firstElement" would be dead wrong. Now, I had a super old version of this (like, years old. insert "deja vu" theme here) that concatenated the names in cases like this, to lengthOrFirstElement, but that was shot down as too easily producing names that are unwieldy as unions grow. And thus, the preference for arg0 was born. It carries no information, thus you can draw no (potentially inaccurate) conclusion as to the usage of the parameter.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If Titian Cernicova-Dragomir (@dragomirtitian) cares enough to fix it, that's good enough for me. =)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me...with the caveat that the minor style issues that stem from combineUnionParameters precedent should be fixed there and here in a followup PR =P

@weswigham

Copy link
Copy Markdown
MemberAuthor

Daniel Rosenwasser (@DanielRosenwasser) I assume you want this to hit 4.3 and not 4.2 at this point - will you LMK when I should merge?

@jcalz

Joe Calzaretta (jcalz) commented Feb 13, 2022

Copy link
Copy Markdown
Contributor

SO Question asks about this strange behavior:

interfaceOvld{(): void;(x: string): void;}constoNo: Ovld=x=>{}// -> ~~~// error! Type '(x: string) => void ' is not assignable to type 'Ovld'.constok: Ovld=(x?: string)=>{}// okay

Playground link

Looks like the contextual signature isn't what I'd expect in the face of differing parameter list lengths. Wondering if this behavior is intended or unintended as per this PR, and if there should be a new issue filed about it.

@forresthopkinsa

Copy link
Copy Markdown

For the sake of search, this also fixes an unmentioned bug (though somewhat similar to the comment from 35641):

constobj={a: ['x'],b: ['y'],}asconst;typeObj=typeofobj;typeKey=keyofObj;typeVal=Obj[Key];typeItem=Val[number];constkeys=Object.keys(obj)asKey[];keys.forEach(key=>{obj[key].forEach(item=>{// Parameter 'item' implicitly has an 'any' type. (7006)console.log(item);});for(constitemofobj[key]){// no error, type inferred correctlyconsole.log(item);}});

Playground

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Author: TeamFor Uncommitted BugPR for untriaged, rejected, closed or missing bug

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

Possible breaking change: assigning array to 1-tuple callbacks should select the right overload

5 participants

@weswigham@typescript-bot@jcalz@forresthopkinsa@sandersn