Skip to content
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

Implement partial type argument inference using the _ sigil #26349

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

weswigham
Copy link
Member

@weswigham weswigham commented Aug 10, 2018

In this PR, we allow the _ sigil to appear in type argument lists in expression positions as a placeholder for locations where you would like inference to occur:

const instance = new Foo<_, string>(0, "");
const result = foo<_, string>(0, "");
const tagged = tag<_, string>`tags ${12} ${""}`;
const jsx = <Component<_, string> x={12} y="" cb={props => void (props.x.toFixed() + props.y.toUpperCase())} />;

This allows users to override a variable in a list of defaulted ones without actually explicitly providing the rest or allow a type variable to be inferred from another provided one.

Implements #26242.
Supersedes #23696.

Fixes #20122.
Fixes #10571.

Technically, this prevents you from passing a type named _ as a type argument (we do not reserve _ in general and don't think we need to). Our suggested workaround is simply to rename or alias the type you wish to pass. Eg,

interface _ { (): UnderscoreStatic; }

foo<_>(); // bad - triggers partial type inference, instead:

type Underscore = _;
foo<Underscore>(); // good

we did a quick check over at big ts query, and didn't find any public projects which passed a type named _ as a type argument in an expression/inference position, so it seems like a relatively safe care-out to make.

Prior work for the _ sigil for partial inference includes flow and f#, so it should end up being pretty familiar.

@alfaproject
Copy link

Why write infer explicitly? Could we do like destructuring? <, string> instead of <infer, string>

By default, it would infer.

@weswigham
Copy link
Member Author

@alfaproject I wrote my rationale down in #26242

@jwbay
Copy link
Contributor

jwbay commented Aug 14, 2018

Would this PR enable this scenario? I didn't see a test quite like it. Basically extracting an inferred type parameter from a specified type parameter.

type Box<T> = { value: T };

type HasBoxedNumber = Box<number>;

declare function foo<T extends Box<S>, S>(arg: T): S;

declare const hbn: HasBoxedNumber;

foo<HasBoxedNumber, infer>(hbn).toFixed();

@weswigham
Copy link
Member Author

Based on the design meeting feedback, this has been swapped to variant 2 from the proposal - using the * sigil as a placeholder for inference. We'll need updates to our tmlanguage to get syntax highlighting right (although we already parsed * in type positions for jsdoc, so we probably should have already).

sheetalkamat added a commit to microsoft/TypeScript-TmLanguage that referenced this pull request Aug 17, 2018
@weswigham
Copy link
Member Author

Would this PR enable this scenario? I didn't see a test quite like it. Basically extracting an inferred type parameter from a specified type parameter.

As is, no. Other type parameters (supplied or no) are not currently inference sites for a type parameter. We could enable it here (just by performing some extra inferType calls between the supplied types and their parameters' constraints), probably, but... should we? @ahejlsberg you have an opinion here?

@ahejlsberg
Copy link
Member

@ahejlsberg you have an opinion here?

I don't think we want constraints to be inference sites, at least not without some explicit indication. At some point we might consider allowing infer declarations in type parameter lists just as we do in conditional types:

type Unbox<T extends Box<infer U>> = U;

Though you can get pretty much the same effect with conditional types:

type Unbox<T extends Box<any>> = T extends Box<infer U> ? U : never;

@weswigham
Copy link
Member Author

Alright, I'll leave this as is then and just mention that it's available as a branch if we ever change our minds in the future.

@weswigham weswigham changed the title Implement partial type argument inference using the infer keyword Implement partial type argument inference using the * sigil Aug 17, 2018
@treybrisbane
Copy link

treybrisbane commented Aug 18, 2018

@weswigham It seems inconsistent (and kinda strange) to use the * sigil for this when we already use the infer keyword to denote explicit type inference...

type Tagged<O extends object, T> = O & { __tag: T };

// "Infer a type, and make it available under the alias 'T'"
declare function getTag<O extends Tagged<any, any>>(object: O): O extends Tagged<any, infer T> ? T : never;

// "Infer a type, and make it available to 'getTag' under the alias at the first type position"
getTag<infer>({ foo: string, __tag: 'bar' })
// => 'bar'

This seems like an obvious syntactic duality to me... What was the reason you instead decided to go with *?

@RyanCavanaugh
Copy link
Member

The existing infer T keyword produces a new binding for T; this wouldn't be available in argument positions (e.g. you can't write getFoo<infer T, T>()). Having the infer keyword have arity 1 in conditional types and arity 0 in type argument positions seems like a decrease in overall consistency rather than an increase.

@KyleDavidE
Copy link

It would probably be nice to be able to declare infer on the functions, ex: function foo<A, B = infer>(b: B, c: SomeComplexType<A,B>): SomeOtherComplexType<A,B>

@treybrisbane
Copy link

@RyanCavanaugh

Having the infer keyword have arity 1 in conditional types and arity 0 in type argument positions seems like a decrease in overall consistency rather than an increase.

Thanks for the response. :)

Fair enough, but I'd argue that this decrease in consistency is far less than that of introducing an entirely new sigil for this purpose. Is there really a benefit to users in using such a radically different syntax for something whose only difference to infer T is the arity?

@treybrisbane
Copy link

Something else to consider is that TypeScript supports JSDoc, and * in JSDoc means any. I'm not sure it's a good idea to reuse a symbol that means any in one context for something that means "please infer this type for me" in another context.

If we're concerned about making operators/keywords context-sensitive, then again it seems like making infer context-sensitive is far less of an evil than doing the same for *.

@insidewhy
Copy link

insidewhy commented Aug 31, 2018

I don't mind * as it jives with flow. Users of typescript can just avoid * in jsdoc and always use any for the purpose easily enough?

I'd also like to see this:

const instance = new Blah<T, **>(1, 'b', false, new Date())

I have a class that bundles many string literal types and I have to enumerate them all at every callsite even when I'm using the code from this branch. Everytime I add a new string literal I have to update every single callsite which is a massive drag ;)

@insidewhy
Copy link

Consider:

type LiteralMap<S1 extends string, S2 extends string, S3 extends string> = {
  item1: S1,
  item2: S2,
  item3: S3
}

With this feature at every definition using this type I have to use:

function user(map: LiteralMap<*, *, *>) {}

Now if I need to add a new literal to my map I have to update this to:

type LiteralMap<S1 extends string, S2 extends string, S3 extends string, S4 extends string> = {
  item1: S1,
  item2: S2,
  item3: S3,
  item4: S4,
}

which is no big deal, but now I also have to update every single use of this to:

function user(map: LiteralMap<*, *, *, *>) {}

With LiteralMap<**> I can just update the definition without affecting every area it is used.

@svieira svieira mentioned this pull request Sep 1, 2018
4 tasks
@xaviergonz
Copy link

xaviergonz commented Sep 1, 2018

Or it could follow the tuple system

type LiteralMap<S1?, S2?, S3?> = {
  item1: S1,
  item2: S2,
  item3: S3
}

function user(map: LiteralMap) {} // infer, infer, infer
function user(map: LiteralMap<boolean>) {} // boolean, infer, infer
function user(map: LiteralMap<_, boolean>) {} // infer, boolean, infer

type LiteralMap<S1, S2, S3?> = {
  item1: S1,
  item2: S2,
  item3: S3
}

function user(map: LiteralMap) {} // not allowed, S1 and S2 missing
function user(map: LiteralMap<boolean>) {} // not allowed, S2 missing
function user(map: LiteralMap<_, boolean>) {} // infer, boolean, infer

alternatively it could use the default assignation (which I guess makes more sense, since if you want it to infer the default type makes no sense?)

type LiteralMap<S1 = _, S2 = _, S3 = _> = {
  item1: S1,
  item2: S2,
  item3: S3
}

function user(map: LiteralMap) {} // infer, infer, infer
function user(map: LiteralMap<boolean>) {} // boolean, infer, infer
function user(map: LiteralMap<*, boolean>) {} // infer, boolean, infer

type LiteralMap<S1, S2, S3 = _> = {
  item1: S1,
  item2: S2,
  item3: S3
}

function user(map: LiteralMap) {} // not allowed, S1 and S2 missing
function user(map: LiteralMap<boolean>) {} // not allowed, S2 missing
function user(map: LiteralMap<_, boolean>) {} // infer, boolean, infer

@niieani
Copy link

niieani commented Sep 12, 2018

Much better than #23696. Great stuff 👍 Thanks!

@cevek
Copy link

cevek commented Sep 20, 2018

@RyanCavanaugh What the problem with this PR? Is this too complicated? I wait this feature more than 2 years. I really need this one in a lot of places. Currently I need to use dirty hacks like

function x<A>() { return <B>(prop: {a: A, b: B})=>void}
x<number>()({a:1, b:'b'})

@weswigham
Copy link
Member Author

@typescript-bot test this
@typescript-bot run dt
@typescript-bot test top100
@typescript-bot perf test this

@typescript-bot
Copy link
Collaborator

typescript-bot commented May 25, 2023

Heya @weswigham, I've started to run the perf test suite on this PR at 814f86c. You can monitor the build here.

Update: The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commented May 25, 2023

Heya @weswigham, I've started to run the parallelized Definitely Typed test suite on this PR at 814f86c. You can monitor the build here.

Update: The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commented May 25, 2023

Heya @weswigham, I've started to run the extended test suite on this PR at 814f86c. You can monitor the build here.

@typescript-bot
Copy link
Collaborator

typescript-bot commented May 25, 2023

Heya @weswigham, I've started to run the diff-based top-repos suite on this PR at 814f86c. You can monitor the build here.

Update: The results are in!

@typescript-bot
Copy link
Collaborator

@weswigham Here are the results of running the top-repos suite comparing main and refs/pull/26349/merge:

Everything looks good!

@typescript-bot
Copy link
Collaborator

@weswigham
The results of the perf run you requested are in!

Here they are:

Compiler

Comparison Report - main..26349
Metric main 26349 Delta Best Worst p-value
Angular - node (v18.10.0, x64)
Memory used 365,809k (± 0.00%) 365,855k (± 0.01%) +46k (+ 0.01%) 365,804k 365,915k p=0.031 n=6
Parse Time 3.42s (± 0.88%) 3.42s (± 0.26%) ~ 3.41s 3.43s p=0.807 n=6
Bind Time 1.11s (± 0.46%) 1.11s (± 0.49%) ~ 1.11s 1.12s p=0.640 n=6
Check Time 8.75s (± 0.32%) 8.78s (± 0.66%) ~ 8.72s 8.86s p=0.469 n=6
Emit Time 7.41s (± 0.74%) 7.44s (± 0.37%) ~ 7.41s 7.48s p=0.228 n=6
Total Time 20.70s (± 0.30%) 20.75s (± 0.43%) ~ 20.65s 20.88s p=0.261 n=6
Compiler-Unions - node (v18.10.0, x64)
Memory used 192,108k (± 1.22%) 192,092k (± 1.23%) ~ 191,099k 196,907k p=0.378 n=6
Parse Time 1.50s (± 1.54%) 1.51s (± 0.94%) ~ 1.49s 1.53s p=0.622 n=6
Bind Time 0.77s (± 0.97%) 0.77s (± 0.67%) ~ 0.77s 0.78s p=0.784 n=6
Check Time 9.48s (± 0.76%) 9.54s (± 0.25%) ~ 9.52s 9.58s p=0.106 n=6
Emit Time 2.76s (± 1.58%) 2.76s (± 0.77%) ~ 2.72s 2.78s p=0.746 n=6
Total Time 14.51s (± 0.75%) 14.59s (± 0.18%) ~ 14.56s 14.62s p=0.220 n=6
Monaco - node (v18.10.0, x64)
Memory used 346,619k (± 0.01%) 346,632k (± 0.00%) ~ 346,611k 346,648k p=0.688 n=6
Parse Time 2.60s (± 1.10%) 2.60s (± 0.83%) ~ 2.57s 2.63s p=0.687 n=6
Bind Time 1.01s (± 1.16%) 1.00s (± 1.67%) ~ 0.97s 1.02s p=0.491 n=6
Check Time 7.16s (± 0.59%) 7.17s (± 0.58%) ~ 7.10s 7.23s p=0.519 n=6
Emit Time 4.23s (± 0.41%) 4.27s (± 0.46%) +0.03s (+ 0.75%) 4.23s 4.28s p=0.034 n=6
Total Time 15.00s (± 0.52%) 15.04s (± 0.34%) ~ 14.99s 15.11s p=0.421 n=6
TFS - node (v18.10.0, x64)
Memory used 300,620k (± 0.01%) 300,608k (± 0.00%) ~ 300,595k 300,619k p=0.228 n=6
Parse Time 2.08s (± 0.83%) 2.06s (± 1.77%) ~ 2.00s 2.09s p=0.416 n=6
Bind Time 1.14s (± 0.36%) 1.14s (± 0.66%) ~ 1.13s 1.15s p=0.389 n=6
Check Time 6.64s (± 0.42%) 6.61s (± 0.56%) ~ 6.55s 6.65s p=0.126 n=6
Emit Time 3.89s (± 0.79%) 3.89s (± 0.68%) ~ 3.86s 3.93s p=1.000 n=6
Total Time 13.76s (± 0.44%) 13.70s (± 0.59%) ~ 13.60s 13.80s p=0.230 n=6
material-ui - node (v18.10.0, x64)
Memory used 481,795k (± 0.02%) 481,755k (± 0.00%) ~ 481,726k 481,786k p=0.378 n=6
Parse Time 3.12s (± 0.62%) 3.13s (± 0.66%) ~ 3.10s 3.15s p=0.511 n=6
Bind Time 0.91s (± 1.20%) 0.92s (± 0.82%) ~ 0.91s 0.93s p=0.084 n=6
Check Time 16.79s (± 0.38%) 16.91s (± 0.51%) +0.12s (+ 0.72%) 16.82s 17.05s p=0.030 n=6
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) ~ 0.00s 0.00s p=1.000 n=6
Total Time 20.81s (± 0.29%) 20.95s (± 0.47%) +0.14s (+ 0.66%) 20.84s 21.12s p=0.024 n=6
xstate - node (v18.10.0, x64)
Memory used 563,019k (± 0.03%) 563,119k (± 0.02%) ~ 562,917k 563,354k p=0.261 n=6
Parse Time 3.81s (± 0.79%) 3.84s (± 0.30%) ~ 3.82s 3.85s p=0.106 n=6
Bind Time 1.63s (± 0.93%) 1.64s (± 0.67%) ~ 1.63s 1.66s p=0.739 n=6
Check Time 2.81s (± 0.49%) 2.81s (± 0.37%) ~ 2.80s 2.83s p=0.869 n=6
Emit Time 0.08s (± 0.00%) 0.08s (± 0.00%) ~ 0.08s 0.08s p=1.000 n=6
Total Time 8.34s (± 0.33%) 8.38s (± 0.26%) +0.03s (+ 0.40%) 8.35s 8.41s p=0.044 n=6
Angular - node (v16.17.1, x64)
Memory used 365,251k (± 0.02%) 365,247k (± 0.01%) ~ 365,165k 365,279k p=0.936 n=6
Parse Time 3.57s (± 0.54%) 3.57s (± 0.23%) ~ 3.56s 3.58s p=0.402 n=6
Bind Time 1.18s (± 0.54%) 1.18s (± 0.46%) ~ 1.18s 1.19s p=0.201 n=6
Check Time 9.59s (± 0.25%) 9.62s (± 0.33%) ~ 9.59s 9.67s p=0.076 n=6
Emit Time 7.94s (± 0.45%) 8.00s (± 0.84%) ~ 7.92s 8.11s p=0.086 n=6
Total Time 22.28s (± 0.12%) 22.38s (± 0.29%) +0.10s (+ 0.45%) 22.27s 22.45s p=0.044 n=6
Compiler-Unions - node (v16.17.1, x64)
Memory used 193,335k (± 0.52%) 192,921k (± 0.02%) ~ 192,887k 192,976k p=1.000 n=6
Parse Time 1.60s (± 1.70%) 1.61s (± 0.61%) ~ 1.60s 1.63s p=1.000 n=6
Bind Time 0.83s (± 0.62%) 0.83s (± 0.62%) ~ 0.82s 0.83s p=1.000 n=6
Check Time 10.21s (± 0.67%) 10.22s (± 0.41%) ~ 10.16s 10.27s p=0.467 n=6
Emit Time 3.01s (± 1.21%) 2.99s (± 0.77%) ~ 2.95s 3.01s p=0.683 n=6
Total Time 15.65s (± 0.47%) 15.65s (± 0.36%) ~ 15.59s 15.71s p=1.000 n=6
Monaco - node (v16.17.1, x64)
Memory used 345,877k (± 0.01%) 345,884k (± 0.00%) ~ 345,864k 345,902k p=0.471 n=6
Parse Time 2.74s (± 0.59%) 2.74s (± 0.50%) ~ 2.72s 2.76s p=0.410 n=6
Bind Time 1.09s (± 1.11%) 1.09s (± 0.77%) ~ 1.08s 1.10s p=0.227 n=6
Check Time 7.86s (± 0.38%) 7.86s (± 0.42%) ~ 7.81s 7.90s p=0.628 n=6
Emit Time 4.47s (± 0.83%) 4.46s (± 0.39%) ~ 4.44s 4.49s p=0.806 n=6
Total Time 16.16s (± 0.49%) 16.15s (± 0.26%) ~ 16.09s 16.21s p=0.936 n=6
TFS - node (v16.17.1, x64)
Memory used 299,953k (± 0.00%) 299,963k (± 0.00%) ~ 299,941k 299,976k p=0.173 n=6
Parse Time 2.19s (± 0.98%) 2.17s (± 0.56%) ~ 2.16s 2.19s p=0.210 n=6
Bind Time 1.24s (± 1.35%) 1.24s (± 0.85%) ~ 1.22s 1.25s p=0.864 n=6
Check Time 7.31s (± 0.61%) 7.30s (± 0.24%) ~ 7.27s 7.32s p=0.806 n=6
Emit Time 4.37s (± 0.80%) 4.37s (± 0.31%) ~ 4.35s 4.39s p=1.000 n=6
Total Time 15.11s (± 0.71%) 15.08s (± 0.21%) ~ 15.03s 15.12s p=0.808 n=6
material-ui - node (v16.17.1, x64)
Memory used 480,996k (± 0.01%) 480,974k (± 0.01%) ~ 480,919k 481,006k p=0.378 n=6
Parse Time 3.26s (± 0.50%) 3.25s (± 0.56%) ~ 3.23s 3.28s p=0.676 n=6
Bind Time 0.94s (± 0.67%) 0.94s (± 0.43%) ~ 0.94s 0.95s p=0.673 n=6
Check Time 17.88s (± 0.79%) 17.91s (± 0.50%) ~ 17.81s 18.06s p=0.575 n=6
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) ~ 0.00s 0.00s p=1.000 n=6
Total Time 22.07s (± 0.71%) 22.10s (± 0.47%) ~ 21.98s 22.28s p=0.873 n=6
xstate - node (v16.17.1, x64)
Memory used 560,649k (± 0.02%) 560,602k (± 0.02%) ~ 560,532k 560,812k p=0.471 n=6
Parse Time 4.00s (± 0.37%) 4.02s (± 0.33%) ~ 4.00s 4.04s p=0.084 n=6
Bind Time 1.76s (± 0.56%) 1.76s (± 0.78%) ~ 1.75s 1.79s p=0.452 n=6
Check Time 3.07s (± 0.48%) 3.06s (± 0.74%) ~ 3.04s 3.09s p=0.516 n=6
Emit Time 0.09s (± 0.00%) 0.09s (± 0.00%) ~ 0.09s 0.09s p=1.000 n=6
Total Time 8.92s (± 0.28%) 8.93s (± 0.30%) ~ 8.90s 8.96s p=0.520 n=6
Angular - node (v14.21.3, x64)
Memory used 359,207k (± 0.00%) 359,219k (± 0.01%) ~ 359,182k 359,255k p=0.471 n=6
Parse Time 3.68s (± 0.76%) 3.67s (± 0.82%) ~ 3.64s 3.72s p=0.624 n=6
Bind Time 1.22s (± 0.42%) 1.22s (± 0.52%) ~ 1.21s 1.23s p=0.386 n=6
Check Time 10.01s (± 0.36%) 10.01s (± 0.52%) ~ 9.95s 10.10s p=1.000 n=6
Emit Time 8.32s (± 0.64%) 8.37s (± 0.97%) ~ 8.27s 8.48s p=0.423 n=6
Total Time 23.23s (± 0.23%) 23.28s (± 0.62%) ~ 23.09s 23.48s p=0.686 n=6
Compiler-Unions - node (v14.21.3, x64)
Memory used 188,276k (± 0.02%) 188,020k (± 0.01%) -256k (- 0.14%) 187,996k 188,067k p=0.005 n=6
Parse Time 1.62s (± 1.08%) 1.62s (± 0.75%) ~ 1.60s 1.63s p=0.802 n=6
Bind Time 0.85s (± 0.00%) 0.85s (± 0.48%) ~ 0.85s 0.86s p=0.405 n=6
Check Time 10.34s (± 0.52%) 10.38s (± 0.15%) ~ 10.37s 10.41s p=0.075 n=6
Emit Time 3.15s (± 0.95%) 3.50s (± 1.58%) +0.35s (+10.99%) 3.44s 3.56s p=0.005 n=6
Total Time 15.96s (± 0.42%) 16.35s (± 0.36%) +0.39s (+ 2.44%) 16.28s 16.41s p=0.005 n=6
Monaco - node (v14.21.3, x64)
Memory used 341,034k (± 0.00%) 341,001k (± 0.01%) -33k (- 0.01%) 340,945k 341,030k p=0.031 n=6
Parse Time 2.81s (± 0.80%) 2.81s (± 0.73%) ~ 2.79s 2.85s p=0.934 n=6
Bind Time 1.12s (± 0.75%) 1.11s (± 0.68%) ~ 1.10s 1.12s p=0.652 n=6
Check Time 8.21s (± 0.21%) 8.18s (± 0.33%) -0.04s (- 0.45%) 8.14s 8.21s p=0.023 n=6
Emit Time 4.70s (± 0.95%) 4.68s (± 0.64%) ~ 4.64s 4.73s p=0.520 n=6
Total Time 16.84s (± 0.26%) 16.79s (± 0.39%) ~ 16.68s 16.87s p=0.127 n=6
TFS - node (v14.21.3, x64)
Memory used 295,140k (± 0.00%) 295,163k (± 0.00%) +23k (+ 0.01%) 295,158k 295,173k p=0.005 n=6
Parse Time 2.41s (± 0.61%) 2.40s (± 0.72%) ~ 2.38s 2.42s p=0.512 n=6
Bind Time 1.07s (± 0.70%) 1.06s (± 0.49%) ~ 1.06s 1.07s p=0.247 n=6
Check Time 7.60s (± 0.51%) 7.61s (± 0.16%) ~ 7.60s 7.63s p=0.746 n=6
Emit Time 4.35s (± 0.81%) 4.38s (± 2.03%) ~ 4.30s 4.54s p=0.809 n=6
Total Time 15.43s (± 0.29%) 15.45s (± 0.61%) ~ 15.35s 15.62s p=0.809 n=6
material-ui - node (v14.21.3, x64)
Memory used 476,558k (± 0.01%) 476,566k (± 0.01%) ~ 476,532k 476,604k p=0.471 n=6
Parse Time 3.35s (± 0.70%) 3.35s (± 0.56%) ~ 3.32s 3.37s p=0.517 n=6
Bind Time 1.00s (± 0.54%) 1.01s (± 0.51%) ~ 1.00s 1.01s p=0.640 n=6
Check Time 18.75s (± 0.51%) 18.88s (± 0.49%) ~ 18.72s 18.96s p=0.066 n=6
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) ~ 0.00s 0.00s p=1.000 n=6
Total Time 23.11s (± 0.46%) 23.22s (± 0.45%) ~ 23.06s 23.31s p=0.078 n=6
xstate - node (v14.21.3, x64)
Memory used 549,591k (± 0.00%) 549,627k (± 0.00%) +36k (+ 0.01%) 549,603k 549,651k p=0.005 n=6
Parse Time 4.25s (± 0.78%) 4.24s (± 0.42%) ~ 4.20s 4.25s p=0.683 n=6
Bind Time 1.60s (± 2.91%) 1.66s (± 1.37%) ~ 1.62s 1.68s p=0.064 n=6
Check Time 3.17s (± 1.04%) 3.19s (± 0.59%) ~ 3.16s 3.21s p=0.195 n=6
Emit Time 0.09s (± 0.00%) 0.09s (± 4.45%) ~ 0.09s 0.10s p=0.405 n=6
Total Time 9.12s (± 0.35%) 9.17s (± 0.29%) +0.05s (+ 0.57%) 9.14s 9.21s p=0.013 n=6
System
Machine Namets-ci-ubuntu
Platformlinux 5.4.0-148-generic
Architecturex64
Available Memory16 GB
Available Memory15 GB
CPUs4 × Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz
Hosts
  • node (v18.10.0, x64)
  • node (v16.17.1, x64)
  • node (v14.21.3, x64)
Scenarios
  • Angular - node (v18.10.0, x64)
  • Angular - node (v16.17.1, x64)
  • Angular - node (v14.21.3, x64)
  • Compiler-Unions - node (v18.10.0, x64)
  • Compiler-Unions - node (v16.17.1, x64)
  • Compiler-Unions - node (v14.21.3, x64)
  • Monaco - node (v18.10.0, x64)
  • Monaco - node (v16.17.1, x64)
  • Monaco - node (v14.21.3, x64)
  • TFS - node (v18.10.0, x64)
  • TFS - node (v16.17.1, x64)
  • TFS - node (v14.21.3, x64)
  • material-ui - node (v18.10.0, x64)
  • material-ui - node (v16.17.1, x64)
  • material-ui - node (v14.21.3, x64)
  • xstate - node (v18.10.0, x64)
  • xstate - node (v16.17.1, x64)
  • xstate - node (v14.21.3, x64)
Benchmark Name Iterations
Current 26349 6
Baseline main 6

TSServer

Comparison Report - main..26349
Metric main 26349 Delta Best Worst p-value
Compiler-UnionsTSServer - node (v18.10.0, x64)
Req 1 - updateOpen 2,534ms (± 0.52%) 2,537ms (± 0.33%) ~ 2,528ms 2,551ms p=0.748 n=6
Req 2 - geterr 5,567ms (± 0.62%) 5,549ms (± 0.44%) ~ 5,524ms 5,592ms p=0.298 n=6
Req 3 - references 336ms (± 0.81%) 336ms (± 0.74%) ~ 333ms 340ms p=0.936 n=6
Req 4 - navto 288ms (± 1.58%) 285ms (± 0.48%) ~ 283ms 287ms p=0.104 n=6
Req 5 - completionInfo count 1,356 (± 0.00%) 1,356 (± 0.00%) ~ 1,356 1,356 p=1.000 n=6
Req 5 - completionInfo 85ms (± 0.99%) 85ms (± 0.96%) ~ 84ms 86ms p=0.718 n=6
CompilerTSServer - node (v18.10.0, x64)
Req 1 - updateOpen 2,659ms (± 1.24%) 2,639ms (± 1.07%) ~ 2,594ms 2,679ms p=0.149 n=6
Req 2 - geterr 4,267ms (± 0.21%) 4,299ms (± 0.43%) +31ms (+ 0.73%) 4,274ms 4,327ms p=0.013 n=6
Req 3 - references 349ms (± 0.57%) 350ms (± 0.36%) ~ 349ms 352ms p=0.131 n=6
Req 4 - navto 291ms (± 0.73%) 290ms (± 0.40%) ~ 289ms 292ms p=0.511 n=6
Req 5 - completionInfo count 1,518 (± 0.00%) 1,518 (± 0.00%) ~ 1,518 1,518 p=1.000 n=6
Req 5 - completionInfo 64ms (± 4.07%) 65ms (± 5.01%) ~ 62ms 69ms p=0.868 n=6
xstateTSServer - node (v18.10.0, x64)
Req 1 - updateOpen 3,079ms (± 0.72%) 3,077ms (± 0.32%) ~ 3,069ms 3,094ms p=0.810 n=6
Req 2 - geterr 1,562ms (± 0.64%) 1,575ms (± 1.11%) ~ 1,552ms 1,597ms p=0.199 n=6
Req 3 - references 115ms (± 1.42%) 114ms (± 1.17%) ~ 112ms 116ms p=0.351 n=6
Req 4 - navto 361ms (± 0.48%) 362ms (± 0.92%) ~ 357ms 366ms p=0.870 n=6
Req 5 - completionInfo count 2,862 (± 0.00%) 2,862 (± 0.00%) ~ 2,862 2,862 p=1.000 n=6
Req 5 - completionInfo 376ms (± 1.61%) 377ms (± 2.26%) ~ 367ms 388ms p=1.000 n=6
Compiler-UnionsTSServer - node (v16.17.1, x64)
Req 1 - updateOpen 2,646ms (± 0.52%) 2,670ms (± 0.73%) ~ 2,647ms 2,700ms p=0.054 n=6
Req 2 - geterr 6,050ms (± 0.75%) 6,011ms (± 0.65%) ~ 5,949ms 6,064ms p=0.229 n=6
Req 3 - references 352ms (± 0.38%) 352ms (± 0.38%) ~ 350ms 354ms p=0.805 n=6
Req 4 - navto 288ms (± 1.40%) 289ms (± 1.55%) ~ 286ms 296ms p=0.870 n=6
Req 5 - completionInfo count 1,356 (± 0.00%) 1,356 (± 0.00%) ~ 1,356 1,356 p=1.000 n=6
Req 5 - completionInfo 93ms (± 1.06%) 93ms (± 0.59%) ~ 92ms 93ms p=0.322 n=6
CompilerTSServer - node (v16.17.1, x64)
Req 1 - updateOpen 2,819ms (± 0.38%) 2,838ms (± 0.73%) ~ 2,812ms 2,864ms p=0.173 n=6
Req 2 - geterr 4,645ms (± 0.24%) 4,671ms (± 0.27%) +25ms (+ 0.55%) 4,653ms 4,687ms p=0.008 n=6
Req 3 - references 364ms (± 0.45%) 366ms (± 0.68%) ~ 362ms 369ms p=0.126 n=6
Req 4 - navto 285ms (± 0.68%) 285ms (± 0.83%) ~ 282ms 288ms p=0.870 n=6
Req 5 - completionInfo count 1,518 (± 0.00%) 1,518 (± 0.00%) ~ 1,518 1,518 p=1.000 n=6
Req 5 - completionInfo 68ms (± 1.21%) 68ms (± 0.81%) ~ 67ms 68ms p=0.859 n=6
xstateTSServer - node (v16.17.1, x64)
Req 1 - updateOpen 3,215ms (± 0.34%) 3,218ms (± 0.40%) ~ 3,207ms 3,242ms p=0.936 n=6
Req 2 - geterr 1,739ms (± 0.73%) 1,745ms (± 0.54%) ~ 1,733ms 1,761ms p=0.574 n=6
Req 3 - references 131ms (± 9.01%) 124ms (± 0.68%) ~ 122ms 124ms p=0.359 n=6
Req 4 - navto 342ms (± 0.50%) 345ms (± 1.07%) ~ 341ms 351ms p=0.104 n=6
Req 5 - completionInfo count 2,862 (± 0.00%) 2,862 (± 0.00%) ~ 2,862 2,862 p=1.000 n=6
Req 5 - completionInfo 416ms (± 0.95%) 402ms (± 1.34%) 🟩-14ms (- 3.25%) 392ms 408ms p=0.006 n=6
Compiler-UnionsTSServer - node (v14.21.3, x64)
Req 1 - updateOpen 2,797ms (± 0.51%) 2,796ms (± 0.49%) ~ 2,781ms 2,813ms p=0.936 n=6
Req 2 - geterr 6,215ms (± 0.94%) 6,211ms (± 0.94%) ~ 6,136ms 6,274ms p=0.689 n=6
Req 3 - references 365ms (± 0.93%) 365ms (± 1.09%) ~ 362ms 373ms p=1.000 n=6
Req 4 - navto 291ms (± 0.40%) 291ms (± 1.57%) ~ 288ms 299ms p=0.371 n=6
Req 5 - completionInfo count 1,356 (± 0.00%) 1,356 (± 0.00%) ~ 1,356 1,356 p=1.000 n=6
Req 5 - completionInfo 100ms (± 4.11%) 98ms (± 6.57%) ~ 86ms 104ms p=0.571 n=6
CompilerTSServer - node (v14.21.3, x64)
Req 1 - updateOpen 2,965ms (± 0.35%) 2,963ms (± 0.43%) ~ 2,945ms 2,980ms p=0.689 n=6
Req 2 - geterr 4,551ms (± 0.82%) 4,513ms (± 0.60%) ~ 4,470ms 4,548ms p=0.093 n=6
Req 3 - references 375ms (± 1.12%) 376ms (± 0.40%) ~ 373ms 377ms p=0.797 n=6
Req 4 - navto 298ms (± 0.35%) 299ms (± 0.41%) ~ 297ms 300ms p=0.247 n=6
Req 5 - completionInfo count 1,518 (± 0.00%) 1,518 (± 0.00%) ~ 1,518 1,518 p=1.000 n=6
Req 5 - completionInfo 77ms (± 1.09%) 77ms (± 3.46%) ~ 75ms 82ms p=0.325 n=6
xstateTSServer - node (v14.21.3, x64)
Req 1 - updateOpen 3,514ms (± 1.24%) 3,522ms (± 0.28%) ~ 3,509ms 3,532ms p=1.000 n=6
Req 2 - geterr 1,856ms (± 0.45%) 1,842ms (± 0.57%) ~ 1,832ms 1,856ms p=0.065 n=6
Req 3 - references 150ms (± 9.00%) 152ms (± 6.29%) ~ 137ms 160ms p=1.000 n=6
Req 4 - navto 394ms (± 0.57%) 393ms (± 0.78%) ~ 390ms 398ms p=0.681 n=6
Req 5 - completionInfo count 2,862 (± 0.00%) 2,862 (± 0.00%) ~ 2,862 2,862 p=1.000 n=6
Req 5 - completionInfo 430ms (± 2.06%) 432ms (± 0.95%) ~ 426ms 438ms p=0.810 n=6
System
Machine Namets-ci-ubuntu
Platformlinux 5.4.0-148-generic
Architecturex64
Available Memory16 GB
Available Memory15 GB
CPUs4 × Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz
Hosts
  • node (v18.10.0, x64)
  • node (v16.17.1, x64)
  • node (v14.21.3, x64)
Scenarios
  • Compiler-UnionsTSServer - node (v18.10.0, x64)
  • Compiler-UnionsTSServer - node (v16.17.1, x64)
  • Compiler-UnionsTSServer - node (v14.21.3, x64)
  • CompilerTSServer - node (v18.10.0, x64)
  • CompilerTSServer - node (v16.17.1, x64)
  • CompilerTSServer - node (v14.21.3, x64)
  • xstateTSServer - node (v18.10.0, x64)
  • xstateTSServer - node (v16.17.1, x64)
  • xstateTSServer - node (v14.21.3, x64)
Benchmark Name Iterations
Current 26349 6
Baseline main 6

Startup

Comparison Report - main..26349
Metric main 26349 Delta Best Worst p-value
tsc-startup - node (v16.17.1, x64)
Execution time 141.59ms (± 0.18%) 141.42ms (± 0.21%) -0.17ms (- 0.12%) 140.59ms 145.32ms p=0.000 n=600
tsserver-startup - node (v16.17.1, x64)
Execution time 220.72ms (± 0.24%) 220.38ms (± 0.18%) -0.34ms (- 0.15%) 219.18ms 224.18ms p=0.000 n=600
tsserverlibrary-startup - node (v16.17.1, x64)
Execution time 223.78ms (± 0.41%) 221.68ms (± 0.17%) -2.10ms (- 0.94%) 220.64ms 226.42ms p=0.000 n=600
typescript-startup - node (v16.17.1, x64)
Execution time 204.07ms (± 0.21%) 203.56ms (± 0.13%) -0.51ms (- 0.25%) 202.84ms 206.54ms p=0.000 n=600
System
Machine Namets-ci-ubuntu
Platformlinux 5.4.0-148-generic
Architecturex64
Available Memory16 GB
Available Memory15 GB
CPUs4 × Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz
Hosts
  • node (v16.17.1, x64)
Scenarios
  • tsc-startup - node (v16.17.1, x64)
  • tsserver-startup - node (v16.17.1, x64)
  • tsserverlibrary-startup - node (v16.17.1, x64)
  • typescript-startup - node (v16.17.1, x64)
Benchmark Name Iterations
Current 26349 6
Baseline main 6

Developer Information:

Download Benchmark

@typescript-bot
Copy link
Collaborator

Hey @weswigham, the results of running the DT tests are ready.
Everything looks the same!
You can check the log here.

@weswigham weswigham requested review from sandersn and andrewbranch and removed request for DanielRosenwasser, ahejlsberg, RyanCavanaugh and a user May 30, 2023 16:45
@shicks
Copy link
Contributor

shicks commented Jun 7, 2023

I've throught quite a bit about partial type inference and I agree that, while this is a good step forward, I have a need for definition-site inference much more often (I suspect the divergence of opinions we've seen upthread is likely splitting across library users vs. library authors - the latter of whom are concerned that requiring the caller to opt into inference doesn't really help in making safe/ergonomic/hard-to-misuse APIs). So I'd also like to see at least some thought toward whether/how this syntax fits in with a hypothetical future definition-site syntax.

FWIW, I put together a gist a while back exploring this (see here, feedback appreciated), and concluded that infer T, while a better analog with the conditional type syntax, doesn't make as much sense because it really is about providing a default. Additionally, for the case mentioned several times upthread where the user should not ever specify this type directly, I proposed a private T = infer (or private T = _, if that placeholder sticks). There's a lot of synergy to considering infer and private together: while each has value on its own, the combination is greater than the sum of its parts.

@d8corp
Copy link

d8corp commented Jun 11, 2023

Can we split generic types by some symbol, like ";".
Before the splitter, generic types that can be provided from outside.
After the splitter, they are never be provided from outside.

declare function foo <
  // available outside
  O extends Record<string, any>;
  // private
  V extends string
> (value: V): O & Record<'value', V>

const test = foo<{ test: true }>('value')
// test: { test: true } & { value: 'value' }

@Alexsey
Copy link

Alexsey commented Jun 13, 2023

Can we split generic types by some symbol, like ";". Before the splitter, generic types that can be provided from outside. After the splitter, they are never be provided from outside.

declare function foo <
  // available outside
  O extends Record<string, any>;
  // private
  V extends string
> (value: V): O & Record<'value', V>

const test = foo<{ test: true }>('value')
// test: { test: true } & { value: 'value' }

Considering that EcmaScript has introduced and TypeScript has adopted an ergonomic # to specify "private" fields in classes, I think it would be intuitive enough to use the same ergonomic approach to specify private type parameters:

declare function foo <
  O extends Record<string, any>,
  #V extends string
> (value: #V): O & Record<'value', #V>

const test = foo<{ test: true }>('value')
// test: { test: true } & { value: 'value' }

@nickmccurdy
Copy link
Contributor

nickmccurdy commented Jun 14, 2023

I'd prefer if TypeScript didn't add non-standard features that look like private class fields, as it may increase usage of private class fields, which don't support certain libraries that rely on Proxies (including Vue).

Alternatively, we could support both # and the private keyword, like TypeScript already does in class declarations.

@d8corp
Copy link

d8corp commented Jun 14, 2023

Can we split generic types by some symbol, like ";". Before the splitter, generic types that can be provided from outside. After the splitter, they are never be provided from outside.

declare function foo <
  // available outside
  O extends Record<string, any>;
  // private
  V extends string
> (value: V): O & Record<'value', V>

const test = foo<{ test: true }>('value')
// test: { test: true } & { value: 'value' }

Considering that EcmaScript has introduced and TypeScript has adopted an ergonomic # to specify "private" fields in classes, I think it would be intuitive enough to use the same ergonomic approach to specify private type parameters:

declare function foo <
  O extends Record<string, any>,
  #V extends string
> (value: #V): O & Record<'value', #V>

const test = foo<{ test: true }>('value')
// test: { test: true } & { value: 'value' }

Looks qualified to me. I suggested ";" like in "for i" loop syntax. Any way, there are no cases to mix private and public types.

I'm not sure about

declare function foo <
  #V extends string,
  O extends Record<string, #V>
> (value: #V): O & Record<'value', #V>

const test = foo<{ test: true }>('value')
// test: { test: true } & { value: 'value' }

@shicks
Copy link
Contributor

shicks commented Jun 14, 2023

This discussion of private generic parameters is getting a bit off-topic to this issue (though as I asserted above, it's tangentially relevant insofar as the syntax should work well together). I am very interested in continuing the private types discussion, but I think it's more appropriate on #42388 so I've moved the discussion there.

As far as this specific issue goes, I'm definitely in favor, don't particularly care about _ vs infer, and would love to see the follow-up of definition-site partial inference happen sooner rather than later.

@emondpph

This comment was marked as off-topic.

@mr-rpl
Copy link

mr-rpl commented Feb 18, 2024

any updates here? would love the ability to partially supply generics while the remainder continue to infer

sirctseb added a commit to sirctseb/crossword that referenced this pull request Feb 19, 2024
…d as the path spec

it all works except that we also take the returned value type as a type parameter, and typescript won't infer
the pathspec string type to the literal passed if you pass the return type. its both or neither.
when microsoft/TypeScript#26349 is merged, this should work
@Bessonov
Copy link

Coming from this issue: #19205 . It would be nice if the inference wouldn't be turned off.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Author: Team Experiment A fork with an experimental idea which might not make it into master Fix Available A PR has been opened for this issue For Uncommitted Bug PR for untriaged, rejected, closed or missing bug
Projects
None yet