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

PickFirst for Union Type or ForEach(Union Item) or spread infer for Union Types #44116

Closed
wesleyolis opened this issue May 17, 2021 · 2 comments
Labels
Declined The issue was declined as something which matches the TypeScript vision Suggestion An idea for TypeScript

Comments

@wesleyolis
Copy link

wesleyolis commented May 17, 2021

Suggestion

I would like to suggest a PickFirst for union Types which will return the first element in the union, which would allow for incremental processing of items in more advance ways. Typically current one can process arrays using type inference.
Such as the following Array Items extends [infer A, ... infer ArrayRemderItems] , one is able to process array items incrementally and can produce and accumulate string type. This is typically the only operator that I think is still missing in which would allow on to manipulated all structures and forms to different types, with no issues. Alternative is simpler one should be less over head ForEach operator. Sure there are many different ways one could look at implementing this, at the moment just limited in all 3 options I can think of.

🔍 Search Terms

ForEach keyof, UnionTypes, Accumulator.

List of keywords you searched for before creating this issue. Write them down here so that others can find this suggestion more easily and help provide feedback.

✅ Viability Checklist

My suggestion meets these guidelines:

  • [✅] This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • [✅] This wouldn't change the runtime behavior of existing JavaScript code
  • [✅] This could be implemented without emitting different JS based on the types of the expressions
  • [✅] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
  • [✅] This feature would agree with the rest of TypeScript's Design Goals.

⭐ Suggestion

📃 Motivating Example

Basically allows on to full re-write types and not just allow there nested depth to be re-written, which full opens up the doors to
collapsing type into one, especially with string literal types manipulators now. Evalute many different forms for MQTT and brokers and things even will be able to do populate and deep populdate properly and anything old dot seperate javascripts methiods.

First approach improve processing of Union types for grouping at top level.

type TUnion = 't1' | 't2' | 't3'

type Eval<T> = [T] extends [infer A, ...infer B] ? A : T

type res = Eval<TUnion> // A = 't1', B = 't2' | 't3'

type res = Eval<'t2'> // A = 't1', B = never, === T, which is 't2'

Alternative, would be for a ForEach, with or with out an accumulator. The concept below.

ForEach[[union types], TypeFunction,  TACCUMULATOR, TInitArgs]  
// Where the Type function is called with its first parameter as the ForEach Item, InitArgs, would  be a parameter to customize the initialization of the remaining parameters of the type function. The ACCUMULATOR, if specified would be the results
There would need to be a specials way to hand the last item, method is called if never,.

type Obj = typeof {KeyA:'KA', KeyB:'KB', KeyC:'KC'}

type ReWrite<T extends string | never> = T extends never ? '':`${T}_` // Maybe implement some logic for with last method needs a call based on type inspection of Rewrite type, including never in its definition.

type PathOrFilterStringValidator<T> = ForEach(string & keys of Obj, ReWrite..)

type res = PathOrFilterStringValidator<Obj>; // 'KeyA_Keyb_keyC_'
type Accum<T extends string, ACC ='',, TFirstCache= PickFirst<T>> = {
'0': TFirstCache extends never 
         ? ACC :
         Accum<Exclude<T, TFirstCache>,`${TFirstCache}_`>
}['0']


type res = Accum<'t1' | 't2' | 't3> // 't1_t2_t3_'

Full ability to capture information and transform it one two axis nested depth and breath of keys can be accumulated into more complex compound structures

💻 Use Cases

Improve more complex string validation and handing of more complex operations with paths and pathWithParams and QueryParams in a Request and deepPopulate and populate, where one is require to capture if parameter is query param
query(paths) // query( 'mainPath' | '${param1}' | '/' | '${param2}/?Query1=',
Other approach is just to use nested object {path:'section',param:{name:'param1':path:....

Further use cases, which allow one ideally to work from datasource to api enpoint across into frontend and back, with out retyping a thing. Ideally one want one validation program that runs database, body, response, and frontend. So only way is really reflection and decorators. Sadly interfaces can't have decorators, so have to use a class with a typecheck that can only use vanilla properties, but can't write a type constraint for class to be data only classes. :-( So we still not there yet.

https://github.com/wesleyolis/mongooseRelationalTypes

@jcalz
Copy link
Contributor

jcalz commented May 17, 2021

This will likely be declined; with it you could implement #13298, which was declined: unions are best thought of as completely unordered. Any underlying ordering is an implementation detail of the compiler and is not meant to be observable.

In fact, such ordering is observable, so you can implement something like PickFirst yourself (it turns out to be more like PickLast). But it is a bad idea: if the type you calculate is dependent on union member order, it can change suddenly out from under you, due to seemingly irrelevant factors. I'm not sure how useful it is to have a type res which is sometimes "t1_t2_t3_" but other times "t2_t1_t3_", or even one that shows up in IntelliSense as "t3_t1_t2_" but is calculated by the type checker as "t3_t2_t1_". 🤮

If the type you calculate is not dependent on the order of the union, then you should try your best to implement it with distributive conditional types before even thinking of iterating the union in some arbitrary order.

@RyanCavanaugh RyanCavanaugh added Declined The issue was declined as something which matches the TypeScript vision Suggestion An idea for TypeScript labels May 27, 2021
@RyanCavanaugh
Copy link
Member

Unions are unordered and any code that attempts to observe a union's order is asking for undefined behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Declined The issue was declined as something which matches the TypeScript vision Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

3 participants