Edit: Remove indexing part
Edit 2: Replace tuple mapping syntax with normal mapped types
Concatentate and merge tuples' entries.
Object.assign's assignee.Array.prototype.concat correctly for tuples.The syntax comes in a few new forms:
[...A, B] appends B to the tuple A. Similarly, [...infer A, any] extends B ? A : [] drops the last item of the tuple and [...any[], infer A] extends B ? A : never extracts the first.{... ...T} for an n-ary merge and [... ...T] an n-ary concatenation.Here's the types for each method I mentioned above.
interface Array<T> {
concat<U extends any[]>(...others: U): [...this, ... ...{[I in keyof U]: (
U[I] extends any[] ? N : U[I] extends ArrayLike<infer R> ? R[] : [U[I]]
)}];
}
interface ObjectConstructor {
assign(target: {... ...typeof sources}, ...sources: object[]): typeof target;
}
My suggestion meets these guidelines:
And finally, merging is just syntax sugar now:
{...A, ...B}↔(& ...[A, B])
I don't think this is correct. It should behave like object spread in JS and override existing properties.
type T = {... {a: string}, ...{a: number}};
// should result in
type T = {a: number};
// instead of
type T = {a: string} & {a: number};
@ajafff Fixed by removing the line. I forgot about that bit.
The 1st part:
I would like to be able to extract and spread in positions other than the last part of a tuple.
Seems to be a duplicate of: #25717 and therefore #1360
@AlCalzone For the first half, probably, but the second half is likely not.
See also #5453 for part 1.
BTW, I updated the proposal to leverage this recently-merged PR.
Converting a tuple to its union, such as with Promise.race's return value.
Doesn't
type TupleTypes<T extends unknown[]> = T[number]
?
work for that?
@weswigham Good catch - no clue how that escaped me. I updated the proposal comment to drop that (and those covered by #26063), but the issue with concatenation and Object.assign still remains.
I changed up the proposed syntax a little, too, to better fit in:
{... ...T}[... ...T]Of course, that space in the middle isn't significant, just explains how it's tokenized.
Converting a tuple to its intersection, such as with Object.assign's assignee.
Ignoring tuples for a second, I want a way to easily convert any union to an intersection. But y'know, I think it is doable, if cumbersome:
type MergeArguments<T, K extends string = "whatever"> =
{
[Key in K]: T extends (first: infer A) => void ? A :
MergeOnePlus<T, K>
}[K];
type MergeOnePlus<T, K extends string> =
{
[Key in K]: T extends (first: infer A, ...args: infer U) => void ? A & MergeArguments<(...args: U) => void, K> :
never
}[K];
type IntoSignature<T extends unknown[]> = (...args: T) => void;
type MergeTupleMembers<T extends unknown[]> = MergeArguments<IntoSignature<T>>;
type SomeTuple = [{ x: 1 }, { y: 2 }, { z: 3 }];
type Merged = MergeTupleMembers<SomeTuple>;
const x: Merged = {
x: 1,
y: 2,
z: 3
};
It's a bit ridiculous, but.... possible.
@weswigham That might very well solve the issue of both concatenation and merging, if I'm reading it correctly.
By any chance, would that still work if you did this to do concatenation?
type ConcatenateOnePlus<T, K extends string> =
{
[Key in K]: T extends (first: infer A, ...args: infer U) => void ? [A, ...ConcatenateArguments<(...args: U) => void, K>] :
never
}[K];
Or would that be dependent on #25717 / #1360?
Ignoring tuples for a second, I want a way to easily convert any union to an intersection
@weswigham check this out:
/**
* @author https://stackoverflow.com/users/2887218/jcalz
* @see https://stackoverflow.com/a/50375286/10325032
*/
type UnionToIntersection<Union> =
(Union extends any
? (argument: Union) => void
: never
) extends (argument: infer Intersection) => void
? Intersection
: never;
I'm working on a utility lib with Merg(Intersection), object only Merg, the well-known symbol iterator walkaround. and type morphing. Please check if they are okay. (this is my first ts lib)
export type Omit2<T, K extends keyof T> = T extends { [Symbol.iterator]: infer U } ? { [Symbol.iterator]: U } & Omit<T, K> : Omit<T, K>;
export type ExcludeO<T extends object, U extends object> =
U extends { [Symbol.iterator]: any } ? Omit<T, keyof U> :
T extends { [Symbol.iterator]: infer IT } ? { [Symbol.iterator]: IT } & Omit<T, keyof U> : Omit<T, keyof U>;
export type ExtractO<T extends object, U extends object> =
U extends { [Symbol.iterator]: any } ? T extends { [Symbol.iterator]: infer IT } ?
{ [Symbol.iterator]: IT } & Pick<T, Extract<keyof T, keyof U>> :
Pick<T, Extract<keyof T, keyof U>> : Pick<T, Extract<keyof T, keyof U>>;
export type Merg<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
export type MergO<U extends object> = (U extends object ? (k: U) => void : never) extends (k: infer T) => void ?
(T extends object ? T : object) : object;
export type UnionTupleType<A extends any[]> = A extends { [n: number]: infer T } ? T extends object ? T : never : never;
export type MergTupleType<A extends any[]> = MergO<UnionTupleType<A>>;
export type Alter<T extends object, U extends object> = ExcludeO<T, U> & ExtractO<U, T>;
export type Extend<T extends object, U extends object> = T & ExcludeO<U, T>;
export type Override<T extends object, U extends object> = ExcludeO<T, U> & U;
export type AlterOver<T extends object, U extends object, X extends object> = Alter<T, ExcludeO<U, X>>;
export type ExtendOver<T extends object, U extends object, X extends object> = Extend<T, ExcludeO<U, X>>;
export type OverrideOver<T extends object, U extends object, X extends object> = Override<T, ExcludeO<U, X>>;
export type AlterLike<T extends object, U extends object, X extends object> = Alter<T, ExtractO<U, X>>;
export type ExtendLike<T extends object, U extends object, X extends object> = Extend<T, ExtractO<U, X>>;
export type OverrideLike<T extends object, U extends object, X extends object> = Override<T, ExtractO<U, X>>;
@weswigham this should fit your need and it enforces object
and they are here
export type MergO<U extends object> = (U extends object ? (k: U) => void : never) extends (k: infer T) => void ? (T extends object ? T : object) : object;
export type UnionTupleType<A extends any[]> = A extends { [n: number]: infer T } ? T extends object ? T : never : never;
export type MergTupleType<A extends any[]> = MergO<UnionTupleType<A>>;
Most helpful comment
@weswigham check this out: