Skip to content

Improved mapped type support for arrays and tuples - #26063

Merged
Anders Hejlsberg (ahejlsberg) merged 4 commits into
masterfrom
mappedTypesArraysTuples
Jul 31, 2018
Merged

Improved mapped type support for arrays and tuples#26063
Anders Hejlsberg (ahejlsberg) merged 4 commits into
masterfrom
mappedTypesArraysTuples

Conversation

@ahejlsberg

Copy link
Copy Markdown
Member

This PR improves our support for arrays and tuples in homomorphic mapped types (i.e. structure preserving mapped types of the form { [P in keyof T]: X }). When a homomorphic mapped type is applied to an array or tuple type, we now produce a corresponding array or tuple type where the element type(s) have been transformed.

type Box<T> = { value: T };
type Boxified<T> = { [P in keyof T]: Box<T[P]> };

type T1 = Boxified<string[]>;  // Box<string>[]
type T2 = Boxified<ReadonlyArray<string>>;  // ReadonlyArray<Box<string>>
type T3 = Boxified<[number, string?]>;  // [Box<number>, Box<string>?]
type T4 = Boxified<[number, ...string[]]>;  // [Box<number>, ...Box<string>[]]
type T5 = Boxified<string[] | undefined>;  // Box<string>[] | undefined
type T6 = Boxified<(string | undefined)[]>;  // Box<string | undefined>[]

Previously, we would treat array and tuple types like regular object types and transform all properties (including methods) of the arrays and tuples. This behavior is rarely if ever desired.

Given a homomorphic mapped type { [P in keyof T]: X }, where T is some type variable, the mapping operation depends on T as follows (the first two rules are existing behavior and the remaining are introduced by this PR):

  • If T is a primitive type no mapping is performed and the result is simply T.
  • If T is a union type we distribute the mapped type over the union.
  • If T is an array type S[] we map to an array type R[], where R is an instantiation of X with S substituted for T[P].
  • If T is an array type ReadonlyArray<S> we map to an array type ReadonlyArray<R>, where R is an instantiation of X with S substituted for T[P].
  • If T is a tuple [S0, S1, ..., Sn] we map to a tuple type [R0, R1, ..., Rn], where each Rx is an instantiation of X with the corresponding Sx substituted for T[P].

Homomorphic mapped types can use ?, -?, or +? annotations to modify the optional-ness of tuple element types. For example, the predefined Partial<T> and Required<T> types have the expected effects on tuple element types:

type T10 = Partial<[number, string]>;  // [number?, string?]
type T11 = Required<[number?, string?]>;  // [number, string]

In --strictNullChecks mode the ?, -?, or +? annotations also add or remove undefined from the element type(s) of arrays and tuples:

type T20 = Partial<string[]>;  // (string | undefined)[]
type T21 = Required<(