Uh oh!
There was an error while loading. Please reload this page.
Implement partial type argument inference using the _ sigil - #26349
Implement partial type argument inference using the _ sigil#26349Wesley Wigham (weswigham) wants to merge 3 commits into
Conversation
João Dias (alfaproject)
commented
Aug 10, 2018
Why write By default, it would infer. |
Wesley Wigham (weswigham)
commented
Aug 10, 2018
João Dias (@alfaproject) I wrote my rationale down in #26242 |
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. typeBox<T>={value: T};typeHasBoxedNumber=Box<number>;declarefunctionfoo<TextendsBox<S>,S>(arg: T): S;declareconsthbn: HasBoxedNumber;foo<HasBoxedNumber,infer>(hbn).toFixed(); |
Wesley Wigham (weswigham)
commented
Aug 17, 2018
Based on the design meeting feedback, this has been swapped to variant 2 from the proposal - using the |
Wesley Wigham (weswigham)
commented
Aug 17, 2018
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 |
Anders Hejlsberg (ahejlsberg)
commented
Aug 17, 2018
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<infer U>>=U;Though you can get pretty much the same effect with conditional types: typeUnbox<TextendsBox<any>>=TextendsBox<infer U> ? U : never; |
Wesley Wigham (weswigham)
commented
Aug 17, 2018
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. |
Wesley Wigham (@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, 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 |
Ryan Cavanaugh (RyanCavanaugh)
commented
Aug 21, 2018
The existing |
KyleDavidE (KyleDavidE)
commented
Aug 22, 2018
It would probably be nice to be able to declare infer on the functions, ex: |
Trey Brisbane (treybrisbane)
commented
Aug 23, 2018
Ryan Cavanaugh (@RyanCavanaugh)
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 |
Trey Brisbane (treybrisbane)
commented
Aug 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 |
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
commented
Sep 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 |
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, inferalternatively 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 |
Bazyli Brzóska (niieani)
commented
Sep 12, 2018
Much better than #23696. Great stuff 👍 Thanks! |
cevek
commented
Sep 20, 2018
Ryan Cavanaugh (@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'}) |
Mike Lysikov (d8corp)
commented
Jun 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' } |
Considering that EcmaScript has introduced and TypeScript has adopted an ergonomic declarefunctionfoo<OextendsRecord<string,any>,
#V extends string
>(value: #V): O&Record<'value', #V>consttest=foo<{test: true}>('value')// test: { test: true } & { value: 'value' } |
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 |
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<
#V extends string,OextendsRecord<string, #V>>(value: #V): O&Record<'value', #V>consttest=foo<{test: true}>('value')// test: { test: true } & { value: 'value' } |
Stephen Hicks (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 |
This would be even cleaner with microsoft/TypeScript#26349
This comment was marked as off-topic.
This comment was marked as off-topic.
Roi Kingon (mr-rpl)
commented
Feb 18, 2024
any updates here? would love the ability to partially supply generics while the remainder continue to infer |
…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
Anton Bessonov (Bessonov)
commented
Apr 20, 2024
Coming from this issue: #19205 . It would be nice if the inference wouldn't be turned off. |
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. |
Martin Johns (MartinJohns)
commented
Aug 3, 2024
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. |
TypeScript Bot (typescript-bot)
commented
Mar 24, 2026
With 6.0 out as the final release vehicle for this codebase, we're closing all PRs that don't fit the merge criteria for post-6.0 patches. If you think this was a mistake and this PR fits the post-6.0 patch criteria, please post to the 6.0 iteration issue with details (specifically, which PR and which patch criteria it satisfies). Next steps for PRs:
|
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 includes flow and f#, so it should end up being pretty familiar.