Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Variadic tuple types#39094

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
ahejlsberg merged 37 commits intomasterfromvariadicTuples
Jun 23, 2020
Merged

Variadic tuple types#39094

ahejlsberg merged 37 commits intomasterfromvariadicTuples
Jun 23, 2020

Conversation

ahejlsberg
Copy link
Member

@ahejlsbergahejlsberg commentedJun 16, 2020
edited
Loading

This PR implementsvariadic tuple types, i.e. the ability for tuple types to have spreads of generic types that can be replaced with actual elements through type instantiation. The PR effectively implements the features discussed in#5453.

Some examples of new capabilities provided in this PR:

// Variadic tuple elementstypeFoo<Textendsunknown[]>=[string, ...T,number];typeT1=Foo<[boolean]>;// [string, boolean, number]typeT2=Foo<[number,number]>;// [string, number, number, number]typeT3=Foo<[]>;// [string, number]// Strongly typed tuple concatenationfunctionconcat<Textendsunknown[],Uextendsunknown[]>(t:[...T],u:[...U]):[...T, ...U]{return[...t, ...u];}constns=[0,1,2,3];// number[]constt1=concat([1,2],['hello']);// [number, number, string]constt2=concat([true],t1);// [boolean, number, number, string]constt3=concat([true],ns);// [boolean, ...number[]]// Inferring parts of tuple typesdeclarefunctionfoo<Textendsstring[],U>(...args:[...T,()=>void]):T;foo(()=>{});// []foo('hello','world',()=>{});// ["hello", "world"]foo('hello',42,()=>{});// Error, number not assignable to string// Inferring to a composite tuple typefunctioncurry<Textendsunknown[],Uextendsunknown[],R>(f:(...args:[...T, ...U])=>R, ...a:T){return(...b:U)=>f(...a, ...b);}constfn1=(a:number,b:string,c:boolean,d:string[])=>0;constc0=curry(fn1);// (a: number, b: string, c: boolean, d: string[]) => numberconstc1=curry(fn1,1);// (b: string, c: boolean, d: string[]) => numberconstc2=curry(fn1,1,'abc');// (c: boolean, d: string[]) => numberconstc3=curry(fn1,1,'abc',true);// (d: string[]) => numberconstc4=curry(fn1,1,'abc',true,['x','y']);// () => number

Structure and instantiation

The basic structure of a non-generic tuple type remains unchanged with this PR: Zero or more required elements, followed by zero or more optional elements, optionally followed by a rest element (for example[A, B?, ...C[]]). However, it is now possible to havevariadic elements anywhere in a tuple type, except following the optional rest element (for example[A, ...T, B?, ...U, ...C[]]).

A variadic elemement is a spread element of the form...T, whereT is a generic type constrained to any array or tuple type (specifically, any type that is assignable toreadonly any[]). Intuitively, a variadic element...T is a placeholder that is replaced with one or more elements through generic type instantiation. Instantiation of a tuple type with a variadic element...T depends on the type argument provided forT as follows:

  • When the type argument forT is a union type, the union is spread over the tuple type. For example,[A, ...T, B] instantiated withX | Y | Z as the type argument forT yields a union of instantiations of[A, ...T, B] withX,Y andZ as the type argument forT respectively.
  • When the type argument is a tuple type,T is replaced with the elements of that tuple type. For example,[A, ...T, B] instantiated with[X, Y] as the type argument forT yields[A, X, Y, B].
  • When the type argument is an array type,T is replaced with a rest element. For example,[A, ...T] instantiated withX[] as the type argument forT yields[A, ...X[]].
  • When the type argument is another generic type,T is simply replaced with that type.
  • When the type argument isany,T is replaced with...any[].
  • When the type argument isnever, the entire result isnever.

Instantiation of a generic tuple type includesnormalization to ensure the resulting tuple type follows the basic structure described above. Specifically:

  • Optionality is removed from any optional elements that precede a required element. For example,[A?, ...T, B?] instantiated with[X, Y?] as the type argument forT yields[A, X, Y?, B?].
  • Rest elements absorb any following elements. For example,[A, ...T, B] instantiated withX[] as the type argument forT yields[A, ...(X | B)[]].
  • Tuples with only a single rest element are reduced to array types. For example,[...X[]] is reduced to simplyX[].

NOTE: With#41544 we now support starting and middle rest elements in tuple types.

Type relationships

Generally, a tuple typeS is related to a tuple typeT by pairwise relating elements ofS to the elements ofT. Variadic elements are processed as follows:

  • A variadic element...U inS is related to a variadic element...V inT ifU is related toV.
  • A variadic element...U inS is related to a rest element...X[] inT ifU is related toX[].

Some examples:

functionfoo1<Textendsunknown[],UextendsT>(x:[string, ...unknown[]],y:[string, ...T],z:[string, ...U]){x=y;// Okx=z;// Oky=x;// Errory=z;// Okz=x;// Errorz=y;// Error}

Tuple types with single variadic elements have the following relations:

  • [...T] is related toT.
  • T is related toreadonly [...T].
  • T is related to[...T] whenT is constrained to a mutable array or tuple type.

Some examples:

functionfoo2<Textendsreadonlyunknown[]>(t:T,m:[...T],r:readonly[...T]){t=m;// Okt=r;// Errorm=t;// Errorm=r;// Errorr=t;// Okr=m;// Ok}

Type inference

Inference between tuple types with the same structure (i.e. same number of elements and fixed, variadic, or rest kind matched to the same kind in each position), simply infers pairwise between the element types. For example, inference from[string, ...Partial<S>, number?] to[string, ...T, number?] infersPartial<S> forT.

Inference between tuple typesS andT with different structure divides each tuple into a starting fixed part, a middle part, and an ending fixed part. Any one of these parts may be empty.

  • The starting fixed parts ofS andT consist of those elements inS andT that are fixed (i.e. neither variadic nor rest elements) in both types matching from the start of each type.

  • IfT contains at least one variadic element andS has no ending rest element, the ending fixed parts ofS andT consist of those elements inS andT that are fixed in both types matching from the end of each type.

  • IfT contains at least one variadic element andS has an ending rest element, the ending fixed part ofT consists of those elements inT that are fixed matching from the end of the type, and the ending fixed part ofS is empty.

  • IfT contains no variadic elements, the ending fixed parts ofS andT are empty.

  • The middle parts ofS andT are those elements inS andT that remain between the starting and ending fixed parts of the types respectively.

Inference then proceeds as follows:

  • Pairwise infer between the elements in the starting parts.

  • If the middle part ofS is a single rest element, infer from that rest element to every element in the middle part ofT.

  • If the middle part ofT is a single variadic or rest element, infer from a tuple consisting of the middle part ofS to that variadic or rest element.

  • If the middle part ofT is exactly two variadic elements...A and...B, and animplied arity exists forA, infer from a tuple consisting of the initial middle part ofS toA and from a tuple consisting of the remaining middle part ofS toB, where the length of the initial middle part corresponds to the implied arity forA.

  • Pairwise infer between the elements in the ending parts, or infer from the rest element inS to the elements of the ending part ofT.

In the context of inference for a call of a generic function with a rest parameterR, the implied arity forR is the number of rest arguments supplied forR. In all other contexts, a type parameter has no implied arity. For an example of inference involving an implied arity, see thecurry function in the introduction.

Some examples:

typeFirst<Textendsreadonlyunknown[]>=T[0];typeDropFirst<Textendsreadonlyunknown[]>=Textendsreadonly[any?, ...inferU] ?U :[...T];typeLast<Textendsreadonlyunknown[]>=Textendsreadonly[...infer_, inferU] ?U :Textendsreadonly[...infer_,(inferU)?] ?U|undefined :undefined;typeDropLast<Textendsreadonlyunknown[]>=Textendsreadonly[...inferU,any?] ?U :[...T];typeT1=First<[number,boolean,string]>;// [number]typeT2=DropFirst<[number,boolean,string]>;// [boolean, string]typeT3=Last<[number,boolean,string]>;// [string]typeT4=DropLast<[number,boolean,string]>;// [number, boolean]

Spreads in array literals

When an array literal has a tuple type, a spread of a value of a generic array-like type produces a variadic element. For example:

functionfoo3<Textendsunknown[],Uextendsunknown[]>(t:[...T],u:[...U]){return[1, ...t,2, ...u,3]asconst;// readonly [1, ...T, 2, ...U, 3]}constt=foo3(['hello'],[10,true]);// readonly [1, string, 2, number, boolean, 3]

When the contextual type of an array literal is a tuple type, a tuple type is inferred for the array literal. The type[...T], whereT is an array-like type parameter, can conveniently be used to indicate a preference for inference of tuple types:

declarefunctionft1<Textendsunknown[]>(t:T):T;declarefunctionft2<Textendsunknown[]>(t:T):readonly[...T];declarefunctionft3<Textendsunknown[]>(t:[...T]):T;declarefunctionft4<Textendsunknown[]>(t:[...T]):readonly[...T];ft1(['hello',42]);// (string | number)[]ft2(['hello',42]);// readonly (string | number)[]ft3(['hello',42]);// [string, number]ft4(['hello',42]);// readonly [string, number]

Indexing and destructuring

Indexing and destructuring of generic tuple types appropriately recognizes fixed elements at the start of the tuple type. Beyond the fixed elements, the type is simply a union of the remaining element types.

functionf1<Textendsunknown[]>(t:[string, ...T],n:number){consta=t[0];// stringconstb=t[1];// [string, ...T][1]constc=t[2];// [string, ...T][2]constd=t[n];// [string, ...T][number]}functionf2<Textendsunknown[]>(t:[string, ...T,number],n:number){consta=t[0];// stringconstb=t[1];// [string, ...T, number][1]constc=t[2];// [string, ...T, number][2]constd=t[n];// [string, ...T, number][number]}functionf3<Textendsunknown[]>(t:[string, ...T]){let[...ax]=t;// [string, ...T]let[b1, ...bx]=t;// string, [...T]let[c1,c2, ...cx]=t;// string, [string, ...T][1], T[number][]}functionf4<Textendsunknown[]>(t:[string, ...T,number]){let[...ax]=t;// [string, ...T, number]let[b1, ...bx]=t;// string, [...T, number]let[c1,c2, ...cx]=t;// string, [string, ...T, number][1], (number | T[number])[]}

Rest parameters and spread arguments

Spread expressions with fixed length tuples are now appropriately flattened in argument lists. For example:

declarefunctionfs1(a:number,b:string,c:boolean, ...d:number[]):void;functionfs2(t1:[number,string],t2:[boolean],a1:number[]){fs1(1,'abc',true,42,43,44);fs1(...t1,true,42,43,44);fs1(...t1, ...t2,42,43,44);fs1(...t1, ...t2, ...a1);fs1(...t1);// Error: Expected at least 3 arguments, but got 2fs1(...t1,45);// Error: Type '45' is not assignable to type 'boolean'}

A rest parameter of a generic tuple type can be used to infer types from the middle part of argument lists. For example:

declarefunctionfr1<Textendsunknown[]>(x:number, ...args:[...T,number]):T;functionfr2<Uextendsunknown[]>(u:U){fr1(1,2);// []fr1(1,'hello',true,2);// [string, boolean]fr1(1, ...u,'hi',2);// [...U, string]fr1(1);// Error: Expected 2 arguments, but got 1}

Application of mapped types

When a mapped type is applied to a generic tuple type, non-variadic elements are eagerly mapped but variadic elements continue to be generic. Effectively,M<[A, B?, ...T, ...C[]] is resolved as[...M<[A]>, ...M<[B?]>, ...M<T>, ...M<C[]>]. For example:

typeTP1<Textendsunknown[]>=Partial<[string, ...T,number]>;// [string?, ...Partial<T>, number?]

Fixes#5453.
Fixes#26113.

matijagrcic, kitos, jayphelps, jasonkuhrt, justinbayctxs, robertt, alex-okrushko, aminpaks, IllusionMH, JirkaVebr, and 229 more reacted with thumbs up emojirowdyrotifer, AwesomeObserver, macabeus, j-oliveras, harrysolovay, Quelklef, raveclassic, fuafa, btoo, millsp, and 19 more reacted with laugh emojiRemyRylan, RyanCavanaugh, paul-sachs, zen0wu, ssnielsen, ddprrt, robertt, alexrock, guywaldman, dderevjanik, and 116 more reacted with hooray emojiorta, matijagrcic, mrmlnc, kitos, jasonkuhrt, alex-okrushko, dpraimeyuu, cartant, JirkaVebr, AwesomeObserver, and 114 more reacted with heart emojirobertt, matijagrcic, dderevjanik, kitos, antonvasin, jasonkuhrt, alex-okrushko, mohsen1, hipstersmoothie, JoshuaKGoldberg, and 58 more reacted with rocket emojibrainkim, jasonkuhrt, alex-okrushko, macabeus, j-oliveras, CYBAI, Quelklef, raveclassic, fuafa, sod, and 11 more reacted with eyes emoji
# Conflicts:#src/compiler/checker.ts#tests/baselines/reference/callWithSpread3.errors.txt#tests/baselines/reference/genericRestParameters1.errors.txt#tests/baselines/reference/ramdaToolsNoInfinite.types
@jdmichaud
Copy link

Will the type ofPromise.all be improved thanks to this?

tonivj5, samhh, and Damvilion reacted with eyes emoji

@w0rp
Copy link

Will the type ofPromise.all be improved thanks to this?

That's a very good example of something that can easily be improved by using this. Maybe someone should raise an issue or create a pull request for it.

@IllusionMH
Copy link
Contributor

It's already discussed in#39788

jdmichaud reacted with thumbs up emoji

@ahejlsberg
Copy link
MemberAuthor

With#41544 we now support rest elements in starting and middle positions of tuple types. This addresses some of the issues that were discussed in this PR, such as#39094 (comment).

dead-claudia, joakim, millsp, and falkenhawk reacted with hooray emoji

facebook-github-bot pushed a commit to facebook/pyre-check that referenced this pull requestFeb 20, 2021
Summary:Problem: To solve `Tuple[int, str, bool, bool] <: Tuple[int, *Ts, int]`, we need to solve `[int, str, bool, bool] <: [int, *Ts, int]`.We do that by removing matching elements of known length from both the prefix and the suffix.In the above example, `int` is in both prefixes, so we extract it. Next, the left side has `str`, which has a known fixed length 1, but the right side has `*Ts`, which doesn't have a known length. So, we don't extract that. Likewise, we can extract the matching suffix of `[bool] vs [int]` since they have known lengths. (We just split by lengths here, without checking for compatibility. That happens in `solve`.)So, after splitting, we get```[int] - [str, bool] - [bool][int] - [   *Ts   ] - [int]```We solve each part pairwise. We check `int <: int`, `[str, bool] <: [*Ts]`, and `bool <: int`.So, we end up solving it as `Ts = Tuple[str, bool]`.There are other cases like unbounded tuples, bound vs free variables, multiple `*Ts`, and so on, but this is the core idea.This is what TypeScript [does](microsoft/TypeScript#39094) for its variadic tuples. Note that we don't yet support unpacking unbounded tuples or concatenation of multiple variadics (that's in a future PEP).Reviewed By: grievejiaDifferential Revision: D26520882fbshipit-source-id: 0df0d74becf3ee2a85caf3819093ccc336a5029d
lbwa added a commit to lbwa/esw that referenced this pull requestJul 18, 2021
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@sandersnsandersnsandersn left review comments

@weswighamweswighamweswigham left review comments

@RyanCavanaughRyanCavanaughRyanCavanaugh left review comments

@DanielRosenwasserDanielRosenwasserDanielRosenwasser approved these changes

Assignees

@ahejlsbergahejlsberg

Labels
Author: TeamFor Milestone BugPRs that fix a bug with a specific milestone
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

Rest elements in generic tuple Proposal: Variadic Kinds -- Give specific types to variadic functions
25 participants
@ahejlsberg@Artazor@RyanCavanaugh@typescript-bot@aminpaks@DanielRosenwasser@IllusionMH@ddprrt@jwbay@AlexAegis@HerringtonDarkholme@amitport@TylorS@sandersn@dead-claudia@millsp@treybrisbane@uhyo@bbrzoska@filipesabella@maxrothman@jcalz@w0rp@jdmichaud@weswigham

[8]ページ先頭

©2009-2025 Movatter.jp