Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Implement partial type argument inference using the _ sigil#26349

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Draft
weswigham wants to merge3 commits intomicrosoft:main
base:main
Choose a base branch
Loading
fromweswigham:partial-inference-round-three

Conversation

@weswigham
Copy link
Member

@weswighamweswigham commentedAug 10, 2018
edited
Loading

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:

constinstance=newFoo<_,string>(0,"");constresult=foo<_,string>(0,"");consttagged=tag<_,string>`tags${12}${""}`;constjsx=<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:typeUnderscore=_;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 includesflow andf#, so it should end up being pretty familiar.

LinusU, jwbay, etienne-dldc, Ailrun, SlurpTheo, alexrock, MichalLytek, mpawelski, strax, KSXGitHub, and 604 more reacted with thumbs up emojijbmusso, schneiderfelipe, IkeyBenz, bfricka, aristocr2t, caburj, rolivegab, Jakob5358, emillaine, JuhG, and 25 more reacted with hooray emojiinsidewhy, Ailrun, raveclassic, rosslovas, Bnaya, csantos42, Yogu, bigopon, Ebuall, cevek, and 194 more reacted with heart emojistavalfi, koloboid, ethanresnick, TwilightOwl, ewnavilae, MatthiasKunnen, Ranguna, prescientmoon, categoricalcat, shirakaba, and 70 more reacted with rocket emojihaltcase, soanvig, Jernik, schickling, eaglus, nitzanhen, jaskp, saitonakamura, misterdev, SebastianPodgajny, and 26 more reacted with eyes emoji
@alfaproject
Copy link

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

By default, it would infer.

dardino, jablko, wzuqui, scaleflake, js2me, alii, MrKomish, Federerer, bkniffler, met4000, and 9 more reacted with thumbs up emojisimeyla, codec4, omeid, Ranguna, supposedly, ezzabuzaid, gnllucena, Isaque-Claudino-dos-Santos, and leonadler reacted with thumbs down emoji

@weswigham
Copy link
MemberAuthor

@alfaproject I wrote my rationale down in#26242

alfaproject, insidewhy, omeid, and leonadler reacted with thumbs up emoji

@jwbay
Copy link
Contributor

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.

typeBox<T>={value:T};typeHasBoxedNumber=Box<number>;declarefunctionfoo<TextendsBox<S>,S>(arg:T):S;declareconsthbn:HasBoxedNumber;foo<HasBoxedNumber,infer>(hbn).toFixed();
ulrichb, luthfianto, vaukalak, chbdetta, and basicdays reacted with thumbs up emoji

@weswigham
Copy link
MemberAuthor

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 requestAug 17, 2018
@weswigham
Copy link
MemberAuthor

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 extrainferType 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 allowinginfer declarations in type parameter lists just as we do in conditional types:

typeUnbox<TextendsBox<inferU>>=U;

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

typeUnbox<TextendsBox<any>>=TextendsBox<inferU> ?U :never;
chbdetta, aiham, and lakardion reacted with thumbs up emojimscottnelson and chbdetta reacted with eyes emoji

@weswigham
Copy link
MemberAuthor

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

@weswighamweswigham changed the titleImplement partial type argument inference using the infer keywordImplement partial type argument inference using the * sigilAug 17, 2018
@treybrisbane
Copy link

treybrisbane commentedAug 18, 2018
edited
Loading

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

typeTagged<Oextendsobject,T>=O&{__tag:T};// "Infer a type, and make it available under the alias 'T'"declarefunctiongetTag<OextendsTagged<any,any>>(object:O):OextendsTagged<any, inferT> ?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*?

mpawelski, pokorm, centigrade-julian-lang, matAtWork, and supposedly reacted with thumbs up emoji

@RyanCavanaugh
Copy link
Member

The existinginfer T keyword produces a new binding forT; this wouldn't be available in argument positions (e.g. you can't writegetFoo<infer T, T>()). Having theinfer 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.

c69, lostfictions, itsMapleLeaf, Ebuall, jbmusso, and supposedly reacted with thumbs up emoji

@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>

supposedly, rhysbrettbowen, and antonbobrov reacted with thumbs up emojidhoulb, matAtWork, mlrawlings, supposedly, and rhysbrettbowen reacted with heart emoji

@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 toinfer T is the arity?

mpawelski, centigrade-julian-lang, SpencerPark, squirly, benjaminjackman, jorroll, trusktr, and supposedly reacted with thumbs up emoji

@treybrisbane
Copy link

Something else to consider is that TypeScript supports JSDoc, and* in JSDoc meansany. I'm not sure it's a good idea to reuse a symbol that meansany 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 makinginfer context-sensitive is far less of an evil than doing the same for*.

mpawelski, KyleDavidE, majelbstoat, iwatakeshi, centigrade-julian-lang, omril1, SpencerPark, c69, que-etc, bradleyayers, and 7 more reacted with thumbs up emoji

@insidewhy
Copy link

insidewhy commentedAug 31, 2018
edited
Loading

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

I'd also like to see this:

constinstance=newBlah<T,**>(1,'b',false,newDate())

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:

typeLiteralMap<S1extendsstring,S2extendsstring,S3extendsstring>={item1:S1,item2:S2,item3:S3}

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

functionuser(map:LiteralMap<*,*,*>){}

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

typeLiteralMap<S1extendsstring,S2extendsstring,S3extendsstring,S4extendsstring>={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:

functionuser(map:LiteralMap<*,*,*,*>){}

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

olaf89, SpencerPark, TobiaszCudnik, jorroll, jonas-scytech, TylorS, and dolma reacted with thumbs up emoji

@svieirasvieira mentioned this pull requestSep 1, 2018
4 tasks
@xaviergonz
Copy link

xaviergonz commentedSep 1, 2018
edited
Loading

Or it could follow the tuple system

typeLiteralMap<S1?,S2?,S3?>={item1:S1,item2:S2,item3:S3}functionuser(map:LiteralMap){}// infer, infer, inferfunctionuser(map:LiteralMap<boolean>){}// boolean, infer, inferfunctionuser(map:LiteralMap<_,boolean>){}// infer, boolean, infertypeLiteralMap<S1,S2,S3?>={item1:S1,item2:S2,item3:S3}functionuser(map:LiteralMap){}// not allowed, S1 and S2 missingfunctionuser(map:LiteralMap<boolean>){}// not allowed, S2 missingfunctionuser(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?)

typeLiteralMap<S1=_,S2=_,S3=_>={item1:S1,item2:S2,item3:S3}functionuser(map:LiteralMap){}// infer, infer, inferfunctionuser(map:LiteralMap<boolean>){}// boolean, infer, inferfunctionuser(map:LiteralMap<*,boolean>){}// infer, boolean, infertypeLiteralMap<S1,S2,S3=_>={item1:S1,item2:S2,item3:S3}functionuser(map:LiteralMap){}// not allowed, S1 and S2 missingfunctionuser(map:LiteralMap<boolean>){}// not allowed, S2 missingfunctionuser(map:LiteralMap<_,boolean>){}// infer, boolean, infer
insidewhy, WhiteAbeLincoln, nandin-borjigin, NWYLZW, and loucadufault reacted with thumbs up emojiinsidewhy, jablko, and doc-sultan reacted with heart emoji

@niieani
Copy link

Much better than#23696. Great stuff 👍 Thanks!

insidewhy reacted with thumbs up emojiolaf89 reacted with thumbs down emoji

@cevek
Copy link

@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

functionx<A>(){return<B>(prop:{a:A,b:B})=>void}x<number>()({a:1,b:'b'})
strax, mpawelski, kgtkr, raveclassic, squirly, twop, SirensOfTitan, ysfaran, supposedly, and missannil reacted with thumbs up emoji

@shicks
Copy link
Contributor

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 thatinfer 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 usershould not ever specify this type directly, I proposed aprivate T = infer (orprivate T = _, if that placeholder sticks). There's a lot of synergy to consideringinfer andprivate together: while each has value on its own, the combination is greater than the sum of its parts.

mturley, juanrgm, Alexsey, Mike-Dax, ssalbdivad, and HansBrende reacted with thumbs up emojimturley reacted with eyes emoji

@d8corp
Copy link

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.

declarefunctionfoo<// available outsideOextendsRecord<string,any>;// privateVextendsstring>(value:V):O&Record<'value',V>consttest=foo<{test:true}>('value')// test: { test: true } & { value: 'value' }

@Alexsey
Copy link

Alexsey commentedJun 13, 2023
edited
Loading

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.

declarefunctionfoo<// available outsideOextendsRecord<string,any>;// privateVextendsstring>(value:V):O&Record<'value',V>consttest=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:

declarefunctionfoo<OextendsRecord<string,any>,  #Vextends string>(value: #V):O&Record<'value', #V>consttest=foo<{test:true}>('value')// test: { test: true } & { value: 'value' }
Andarist, niko278, KubaJastrz, piotrwitek, haltcase, TylorS, mturley, shicks, calebeby, Liam-Scott-Russell, and 4 more reacted with thumbs up emojishicks reacted with eyes emoji

@nickserv
Copy link
Contributor

nickserv commentedJun 14, 2023
edited
Loading

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 theprivate keyword, like TypeScript already does in class declarations.

@d8corp
Copy link

d8corp commentedJun 14, 2023
edited
Loading

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.

declarefunctionfoo<// available outsideOextendsRecord<string,any>;// privateVextendsstring>(value:V):O&Record<'value',V>consttest=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:

declarefunctionfoo<OextendsRecord<string,any>,  #Vextends string>(value: #V):O&Record<'value', #V>consttest=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

declarefunctionfoo<  #Vextends string,OextendsRecord<string, #V>>(value: #V):O&Record<'value', #V>consttest=foo<{test:true}>('value')// test: { test: true } & { value: 'value' }

@shicks
Copy link
Contributor

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_ vsinfer, and would love to see the follow-up of definition-site partial inference happen sooner rather than later.

nickserv, mturley, basicdays, DB-Vadim-Wagner, niieani, akd-io, quintal-william, juanrgm, dgopsq, 1-WEEK, and 7 more reacted with thumbs up emoji

Tjstretchalot added a commit to meetoseh/frontend-web that referenced this pull requestJun 23, 2023
@emondpph

This comment was marked as off-topic.

@mr-rpl
Copy link

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

jacobmolby, Tyrenn, Losses, mturley, sirctseb, TrovisTV, codethief, jmalvinez, laukondrup, arthur-fontaine, and 29 more reacted with thumbs up emojiMartinJohns reacted with thumbs down emoji

sirctseb added a commit to sirctseb/crossword that referenced this pull requestFeb 19, 2024
…d as the path specit all works except that we also take the returned value type as a type parameter, and typescript won't inferthe pathspec string type to the literal passed if you pass the return type. its both or neither.whenmicrosoft/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.

haltcase, falahati, orangebokov, alexbown, jarpoole, oceandrama, and MaximSagan reacted with thumbs up emoji

@ChibiBlasphem
Copy link

Any news on this topic? Following the issue for years. It would be great to have insight on whether this is approved or not. Seeing the comments here this feature seems quite demanded. How it's done is another thing.

Tyrenn, orangebokov, KubaJastrz, castarco, oceandrama, MaximSagan, DavideCanton, jacekwilczynski, JMPSequeira, Akatroj, and 3 more reacted with thumbs up emojiMartinJohns, Naddiseo, and JoshuaKGoldberg reacted with thumbs down emoji

@MartinJohns
Copy link
Contributor

@ChibiBlasphem Please readhttps://github.com/microsoft/TypeScript/wiki/FAQ#any-updates.

JoshuaKGoldberg, lukekarrys, and GerkinDev reacted with thumbs up emojiawerlogus, orangebokov, castarco, oceandrama, MaximSagan, DavideCanton, jacekwilczynski, stephenwade, Akatroj, Tiedye, and 5 more reacted with thumbs down emoji

@sandersn
Copy link
Member

All the recent activity on this PR has been design discussion. I think we should close this and go back to design to get something workable there.

treybrisbane and prc5 reacted with thumbs up emojitonivj5, KubaJastrz, Xample, and alii reacted with eyes emoji

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

Reviewers

@sandersnsandersnAwaiting requested review from sandersn

@andrewbranchandrewbranchAwaiting requested review from andrewbranch

Copilot code reviewCopilotAwaiting requested review from CopilotCopilot will automatically review once the pull request is marked ready for review

At least 1 approving review is required to merge this pull request.

Assignees

@weswighamweswigham

Labels

Author: TeamExperimentA fork with an experimental idea which might not make it into masterFix AvailableA PR has been opened for this issueFor Uncommitted BugPR for untriaged, rejected, closed or missing bug

Projects

None yet

Milestone

Backlog

Development

Successfully merging this pull request may close these issues.

Allow skipping some generics when calling a function with multiple generics Granular inference for generic function type arguments

78 participants

@weswigham@alfaproject@jwbay@ahejlsberg@treybrisbane@RyanCavanaugh@KyleDavidE@insidewhy@xaviergonz@niieani@cevek@michaeljota@arogg@fahadash@sledorze@sonhanguyen@Jessidhia@MaxGraey@voliva@freund17@ExE-Boss@denisw@benjaminjackman@artembatura@nandin-borjigin@nickbclifford@trusktr@fwh1990@szszoke@dhoulb@jesseoh@Ranguna@Losses@alvis@satanTime@zachkirsch@kotarella1110@awerlogus@AustP@MrLoh@jamiepine@ivoiv@tannerlinsley@Ericnr@yeegor@btoo@Andarist@jamesopstad@1valdis@akd-io@keithlayne@aradalvand@yume-chan@ilyha81@cmolina@Federerer@mdecurtins@ChibiBlasphem@rolivegab@ipb26@Thundercraft5@typescript-bot@ralusek@patroza@phryneas@ssalbdivad@ysfaran@Peeja@mturley@shicks@d8corp@Alexsey@nickserv@emondpph@mr-rpl@Bessonov@MartinJohns@sandersn

[8]ページ先頭

©2009-2025 Movatter.jp