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

Allow tuple and string types to be concat'ed. #16746

Closed
Arlen22 opened this issue Jun 26, 2017 · 10 comments
Closed

Allow tuple and string types to be concat'ed. #16746

Arlen22 opened this issue Jun 26, 2017 · 10 comments
Labels
Duplicate An existing issue was already created

Comments

@Arlen22
Copy link

Arlen22 commented Jun 26, 2017

TypeScript Version: 2.3.4

Code

function newTuple<T0>(item0: T0): [T0];
function newTuple<T0, T1>(item0: T0, item1: T1): [T0, T1];
function newTuple<T0, T1, T2>(item0: T0, item1: T1, item2: T2): [T0, T1, T2];
function newTuple<T0, T1, T2, T3>(item0: T0, item1: T1, item2: T2, tem3: T3): [T0, T1, T2, T3];
function newTuple<T0, T1, T2, T3, T4>(item0: T0, item1: T1, item2: T2, tem3: T3, item4: T4): [T0, T1, T2, T3, T4];
function newTuple<T0, T1, T2, T3, T4, T5>(item0: T0, item1: T1, item2: T2, tem3: T3, item4: T4, item5: T5): [T0, T1, T2, T3, T4, T5];
function newTuple<T0, T1, T2, T3, T4, T5, T6>(item0: T0, item1: T1, item2: T2, tem3: T3, item4: T4, item5: T5, item6: T6): [T0, T1, T2, T3, T4, T5, T6];
function newTuple<T0, T1, T2, T3, T4, T5, T6, T7>(item0: T0, item1: T1, item2: T2, tem3: T3, item4: T4, item5: T5, item6: T6, item7: T7): [T0, T1, T2, T3, T4, T5, T6, T7];
function newTuple<T0, T1, T2, T3, T4, T5, T6, T7, T8>(item0: T0, item1: T1, item2: T2, tem3: T3, item4: T4, item5: T5, item6: T6, item7: T7, item8: T8): [T0, T1, T2, T3, T4, T5, T6, T7, T8];
function newTuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>(item0: T0, item1: T1, item2: T2, tem3: T3, item4: T4, item5: T5, item6: T6, item7: T7, item8: T8, item9: T9): [T0, T1, T2, T3, T4, T5, T6, T7, T8, T9];
// overload declaration summerized for readability
function newTuple<T0, ..., T9, TR>(item0: T0, ... , item9: T9, restTuple: TR): [T0, ... , T9] + TR;
function newTuple(...args: any[]): any {
    //it will never be more than one deep because function arguments are resolved
    //before the function call
    if (args.length === 11) {
        return args.concat(args.pop());
    } else {
        return args;
    }
}
const test = newTuple("", "", "", "", "", "", "", "", "", "", newTuple("", 0, "", "test" as "test", "test"));

Feature request:

I would like to request a new way of combining tuples. The plus (+) operator. Currently this is the way strings are concatenated and numbers are summed. Therefore it seemed like a logical way to concatenate two tuple types. It should at least apply to Tuple and Array types, and the string type could definitely make use of it as well. For an array, it would be equivalent to Array<A | B>.

Also, the function Array#concat should make use of this operator if possible so that Tuples can easily be concat'ed in value as well as type.

Current behavior when combining two tuple types using &:

If we add more types, it becomes even more laborious at t11.

var t0 = test[0]; // type: string
var t1 = test[1]; // type: string & number
var t2 = test[2]; // type: string
var t3 = test[3]; // type: string & "test"
var t4 = test[4]; // type: string
var t5 = test[5]; // type: string
var t6 = test[6]; // type: string
var t7 = test[7]; // type: string
var t8 = test[8]; // type: string
var t9 = test[9]; // type: string
var t10 = test[10]; // type: string | (string & number)
var t11 = test[11]; // type: string | (string & number)
var t12 = test[12]; // type: string | (string & number)
var t13 = test[13]; // type: string | (string & number)
var t14 = test[14]; // type: string | (string & number)
var t15 = test[15]; // type: string | (string & number)
var t16 = test[16]; // type: string | (string & number)
var t17 = test[17]; // type: string | (string & number)
// repeats t17 on up.
@Arlen22
Copy link
Author

Arlen22 commented Jun 26, 2017

The idea came from this issue: #16389

@ghost
Copy link

ghost commented Jun 26, 2017

Are you asking for an expression operator or a type operator?
Could the issue be simplified to just wanting the following code to compile?

const x: [number, string] = [0, "0"];
const y: [number, string] = [1, "1"];
const z: [number, string, number, string] = [...x, ...y]; // Error (currently)

But currently that would not be right because an array with 3 elements is assignable to a tuple with only 2 elements. See #6229.
Related: #5331.

@Arlen22
Copy link
Author

Arlen22 commented Jun 26, 2017

Well, that code should also compile, but it isn't quite what I want. The closest thing that I have currently found is to define a new tuple like this: [data, state] as [typeof data, typeof state]. That's getting close but I want a way to not have to explicitly type it each time.

I really don't know how much use there is for this operator in tuples, but I can see a LOT of possibilities for strings. But it seemed logical, and an easy way to prevent retyping any code and still keep type checking.

Of course, this would be nice too: new Tuple<...TA>(...items: TA) which would result in [typeof TA[0], typeof TA[1], typeof TA[2]].

@ghost
Copy link

ghost commented Jun 26, 2017

I really don't know how much use there is for this operator in tuples

Me either ... tuples with more than 3 elements are generally a bad idea, so I can't see of much use for concatting tuples together. However, it would likely fall out of variadic function magic.

function f<T>(...args: T): T { return args; }
f(...tuple1, ...tuple2);

I can see a LOT of possibilities for strings

Could you give some examples where it would be useful to add values with string literal types?

@Arlen22
Copy link
Author

Arlen22 commented Jun 26, 2017

Could you give some examples where it would be useful to add values with string literal types?

Assuming you mean concat (instead of add), I am thinking of cases where you might have two options combining together into a string of selectors. This would be an easy way to combine options in a shopping cart for instance.

type size = "Small" | "Medium" | "Large";
type color = "Red" | "Green" | "Blue";

const options: (size + color)[] = [];
//options will be an array of "SmallRed" | "SmallGreen" | "SmallBlue" | "MediumRed" | ...

Of course, options usually get loaded from a database, but there are other use cases. Anywhere you want to hash a 2D array of options.

@Arlen22 Arlen22 changed the title Allow tuple types to be concat'ed. Allow tuple and string types to be concat'ed. Jun 26, 2017
@Arlen22
Copy link
Author

Arlen22 commented Jun 26, 2017

tuples with more than 3 elements are generally a bad idea

Then that removes the need for a TupleRest variable. I think you're right. The most I usually use is 4 (never 10) and I mostly use them when I want to use the values without worrying about the variable name.

@ghost
Copy link

ghost commented Jun 27, 2017

Getting all combinations could be bad for performance. Would you write a switch statement with a case for every one of those? Or would you just have to parse it back anyway, in which case it might as well just be of type string?

@masaeedu
Copy link
Contributor

However, it would likely fall out of variadic function magic.

@andy-ms It might fall out the other way. It is already possible using type recursion to make "variadic" curried functions, like so:

interface Pop<TVarStack extends VarStack> {
    (a: TVarStack["head"]): Pop<TVarStack["tail"]>
}

interface VarStack<THead = any, TTail extends (void | VarStack) = any> {
    head: THead
    tail: TTail
    <TNew>(a: TNew): VarStack<TNew, this>
    (): (a: Pop<this>) => any
}

// Figure out implementation later :)
let stack: VarStack<void, void>;
const pop = stack(new Date())(10)("Bob's")("your")("uncle")()

// a, b, c, d, e are well-typed
pop(a => b => c => d => e => {
    // Need this because can't figure out how to encode base-case in Pop recursion
    return stack
})

There's some stuff I can't figure out, such as how to base-case the recursion, but you can see the foundations are there. What I really want is to transform my recursively nested type into an array type, instead of a function type as I'm doing here. Something like type AsArray<TVarStack extends VarStack> = [TVarStack["head"]] + AsArray<TVarStack["tail"]>.

@mhegazy
Copy link
Contributor

mhegazy commented Aug 17, 2017

looks like this should be covered by #5453

@mhegazy mhegazy added the Duplicate An existing issue was already created label Aug 17, 2017
@mhegazy
Copy link
Contributor

mhegazy commented Sep 5, 2017

Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.

@mhegazy mhegazy closed this as completed Sep 5, 2017
@microsoft microsoft locked and limited conversation to collaborators Jun 14, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

3 participants