-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
Tuples in rest parameters and spread expressions #24897
Conversation
thanks for your great working🤩 |
This looks incredible and I can't wait to make use of this.
That sounds amazing - this would allow us to type the return value of split(delimiter: string): [string, string*] In a world where we have #13778, that would mean the types for destructured split would be correctly inferred: // [string, string | undefined]
const [package, version] = 'typescript@2.9.0'.split('@') The |
Great!, const f1 = bind(f2, "hello"); // (z: boolean) => void |
Great work! Now TypeScript is one step closer to #5453! Rather than having |
Or just have multiple rest arguments: |
But tuples can't be infinite by definition? |
# Conflicts: # tests/baselines/reference/api/tsserverlibrary.d.ts # tests/baselines/reference/api/typescript.d.ts
@goodmind before this PR, tuples are fixed sized. |
@jovdb Yes, that was a typo. Now fixed. Thanks for catching. |
@ahejlsberg can this be used to type |
@felixfbecker @Cryrivers There are two ways we could go on the syntax for the last element in an open-ended tuple: [string, number*]
[string, ...number[]] The latter is longer but certainly makes it easier to see the connection to rest parameters. If we go with the latter, the last element will be required to have an array type. This PR will specifically not permit the equivalent of generic rest parameters in tuples--that would add considerable complexity. But certainly the |
I think the last type being required to be an array is perfectly acceptable. |
This is a wonderful step forward! +1 to the Potential extensions needed for the functions @goodmind mentioned:
(^ or using a generic |
I believe that the better choice for the open-ended tuple syntax is Star has two benefits: arguably better syntax, and preventing generic rest parameters (edit: for now 😝). The latter is solved as @ahejlsberg notes by always requiring the last element to have an array type, which I think is a reasonable restriction. Syntactically, I guess I think we should just adopt the javascripty syntax that will be intuitive to those with experience using rest/spread and is a pure subset of existing proposals for variadic types and others. |
With #26676 the type of rest parameter can now be a union of tuple types. This effectively provides a form of overloading expressed in a single function signature. |
T["length"] example type Take<N extends number, T extends any[], R extends any[]=[]> = {
0: Reverse<R>,
1: Take<N, Tail<T>, Cons<Head<T>, R>>
}[T extends [] ? 0 : R["length"] extends N ? 0 : 1];
export type Group<N extends number, T extends any[], R1 extends any[]=[], R2 extends any[]=[]> = {
0: Reverse<R2>,
1: Group<N, T, [], Cons<Reverse<R1>, R2>>,
2: Group<N, Tail<T>, Cons<Head<T>, R1>, R2>
}[T extends [] ? R1 extends [] ? 0 : 1 : (R1["length"] extends N ? 1 : 2)];
export type Drop<N extends number, T extends any[], R extends any[]=[]> = {
0: T,
1: Drop<N, Tail<T>, Cons<Head<T>, R>>
}[T extends [] ? 0 : R["length"] extends N ? 0 : 1];
|
Hello - this fix apparently makes this possible: #24897 but I can't for the life of me figure out how and that thread has been closed now. I am trying to implement a signal that is used in the following way:
So basically emit uses rest arguments that are typed when the signal is created. Could someone point me in the right direction regarding what the generics for this might look like? Many thanks! |
This PR includes the following:
With these features it becomes possible to strongly type a number of higher-order functions that transform functions and their parameter lists (such as JavaScript's
bind
,call
, andapply
).The PR implements the a number of the capabilities discussed in #5453, but with considerably less complexity.
Rest parameters with tuple types
When a rest parameter has a tuple type, the tuple type is expanded into a sequence of discrete parameters. For example the following two declarations are equivalent:
EDIT: With #26676 the type of rest parameter can be a union of tuple types. This effectively provides a form of overloading expressed in a single function signature.
Spread expressions with tuple types
When a function call includes a spread expression of a tuple type as the last argument, the spread expression corresponds to a sequence of discrete arguments of the tuple element types. Thus, the following calls are equivalent:
Generic rest parameters
A rest parameter is permitted to have a generic type that is constrained to an array type, and type inference can infer tuple types for such generic rest parameters. This enables higher-order capturing and spreading of partial parameter lists:
In the declaration of
f2
above, type inference infers typesnumber
,[string, boolean]
andvoid
forT
,U
andV
respectively.Note that when a tuple type is inferred from a sequence of parameters and later expanded into a parameter list, as is the case for
U
, the original parameter names are used in the expansion (however, the names have no semantic meaning and are not otherwise observable).Optional elements in tuple types
Tuple types now permit a
?
postfix on element types to indicate that the element is optional:In
--strictNullChecks
mode, a?
modifier automatically includesundefined
in the element type, similar to optional parameters.A tuple type permits an element to be omitted if it has a postfix
?
modifier on its type and all elements to the right of it also have?
modifiers.When tuple types are inferred for rest parameters, optional parameters in the source become optional tuple elements in the inferred type.
The
length
property of a tuple type with optional elements is a union of numeric literal types representing the possible lengths. For example, the type of thelength
property in the tuple type[number, string?, boolean?]
is1 | 2 | 3
.Rest elements in tuple types
EDIT: Updated to reflect change from
string*
to...string[]
syntax for rest elements.The last element of a tuple type can be a rest element of the form
...X
, whereX
is an array type. A rest element indicates that the tuple type is open-ended and may have zero or more additional elements of the array element type. For example,[number, ...string[]]
means tuples with anumber
element followed by any number ofstring
elements.The type of the
length
property of a tuple type with a rest element isnumber
.Strong typing of bind, call, and apply
With this PR it becomes possible to strongly type the
bind
,call
, andapply
methods on function objects. This is however a breaking change for some existing code so we need to investigate the repercussions.Fixes #1024.
Fixes #4130.
Fixes #5331.