- Notifications
You must be signed in to change notification settings - Fork13.1k
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
base:main
Are you sure you want to change the base?
Conversation
alfaproject commentedAug 10, 2018
Why write By default, it would infer. |
@alfaproject I wrote my rationale down in#26242 |
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(); |
Based on the design meeting feedback, this has been swapped to variant 2 from the proposal - using the |
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 |
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 typeUnbox<TextendsBox<inferU>>=U; Though you can get pretty much the same effect with conditional types: typeUnbox<TextendsBox<any>>=TextendsBox<inferU> ?U :never; |
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. |
treybrisbane commentedAug 18, 2018 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
@weswigham It seems inconsistent (and kinda strange) to use the 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 |
The existing |
KyleDavidE commentedAug 22, 2018
It would probably be nice to be able to declare infer on the functions, ex: |
treybrisbane commentedAug 23, 2018
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 |
treybrisbane commentedAug 23, 2018
Something else to consider is that TypeScript supports JSDoc, and If we're concerned about making operators/keywords context-sensitive, then again it seems like making |
insidewhy commentedAug 31, 2018 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
I don't mind 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 commentedSep 1, 2018
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<*,*,*,*>){} With |
xaviergonz commentedSep 1, 2018 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
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 |
niieani commentedSep 12, 2018
Much better than#23696. Great stuff 👍 Thanks! |
cevek commentedSep 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 functionx<A>(){return<B>(prop:{a:A,b:B})=>void}x<number>()({a:1,b:'b'}) |
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 |
d8corp commentedJun 11, 2023
Can we split generic types by some symbol, like ";". declarefunctionfoo<// available outsideOextendsRecord<string,any>;// privateVextendsstring>(value:V):O&Record<'value',V>consttest=foo<{test:true}>('value')// test: { test: true } & { value: 'value' } |
Alexsey commentedJun 13, 2023 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Considering that EcmaScript has introduced and TypeScript has adopted an ergonomic declarefunctionfoo<OextendsRecord<string,any>, #Vextends string>(value: #V):O&Record<'value', #V>consttest=foo<{test:true}>('value')// test: { test: true } & { value: 'value' } |
nickserv commentedJun 14, 2023 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
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 |
d8corp commentedJun 14, 2023 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
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' } |
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 |
This would be even cleaner withmicrosoft/TypeScript#26349
This comment was marked as off-topic.
This comment was marked as off-topic.
mr-rpl commentedFeb 18, 2024
any updates here? would love the ability to partially supply generics while the remainder continue to infer |
…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 commentedApr 20, 2024
Coming from this issue:#19205 . It would be nice if the inference wouldn't be turned off. |
ChibiBlasphem commentedAug 3, 2024
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. |
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. |
Uh oh!
There was an error while loading.Please reload this page.
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: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,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.