3.8 Specifying Types

Types are specified either by referencing their keyword or name, or by writing object type literals, array type literals, tuple type literals, function type literals, constructor type literals, or type queries.

  Type:   UnionOrIntersectionOrPrimaryType   FunctionType   ConstructorType

  UnionOrIntersectionOrPrimaryType:   UnionType   IntersectionOrPrimaryType

  IntersectionOrPrimaryType:   IntersectionType   PrimaryType

  PrimaryType:   ParenthesizedType   PredefinedType   TypeReference   ObjectType   ArrayType   TupleType   TypeQuery   ThisType

  ParenthesizedType:   (Type)

Parentheses are required around union, intersection, function, or constructor types when they are used as array element types; around union, function, or constructor types in intersection types; and around function or constructor types in union types. For example:

  1. (string | number)[]
  2. ((x: string) => string) | ((x: number) => number)
  3. (A | B) & (C | D)

The different forms of type notations are described in the following sections.

3.8.1 Predefined Types

The any, number, boolean, string, symbol and void keywords reference the Any type and the Number, Boolean, String, Symbol, and Void primitive types respectively.

  PredefinedType:   any   number   boolean   string   symbol   void

The predefined type keywords are reserved and cannot be used as names of user defined types.

3.8.2 Type References

A type reference references a named type or type parameter through its name and, in the case of a generic type, supplies a type argument list.

  TypeReference:   TypeName[no LineTerminator here]TypeArgumentsopt

  TypeName:   IdentifierReference   NamespaceName.IdentifierReference

  NamespaceName:   IdentifierReference   NamespaceName.IdentifierReference

A TypeReference consists of a TypeName that a references a named type or type parameter. A reference to a generic type must be followed by a list of TypeArguments (section 3.6.2).

A TypeName is either a single identifier or a sequence of identifiers separated by dots. In a type name, all identifiers but the last one refer to namespaces and the last identifier refers to a named type.

Resolution of a TypeName consisting of a single identifier is described in section 2.4.

Resolution of a TypeName of the form N.X, where N is a NamespaceName and X is an IdentifierReference, proceeds by first resolving the namespace name N. If the resolution of N is successful and the export member set (sections 10.4 and 11.3.4.4) of the resulting namespace contains a named type X, then N.X refers to that member. Otherwise, N.X is undefined.

Resolution of a NamespaceName consisting of a single identifier is described in section 2.4. Identifiers declared in namespace declarations (section 10.1) or import declarations (sections 10.3, 11.3.2, and 11.3.3) may be classified as namespaces.

Resolution of a NamespaceName of the form N.X, where N is a NamespaceName and X is an IdentifierReference, proceeds by first resolving the namespace name N. If the resolution of N is successful and the export member set (sections 10.4 and 11.3.4.4) of the resulting namespace contains an exported namespace member X, then N.X refers to that member. Otherwise, N.X is undefined.

A type reference to a generic type is required to specify exactly one type argument for each type parameter of the referenced generic type, and each type argument must be assignable to (section 3.11.4) the constraint of the corresponding type parameter or otherwise an error occurs. An example:

  1. interface A { a: string; }
  2. interface B extends A { b: string; }
  3. interface C extends B { c: string; }
  4. interface G<T, U extends B> {
  5. x: T;
  6. y: U;
  7. }
  8. var v1: G<A, C>; // Ok
  9. var v2: G<{ a: string }, C>; // Ok, equivalent to G<A, C>
  10. var v3: G<A, A>; // Error, A not valid argument for U
  11. var v4: G<G<A, B>, C>; // Ok
  12. var v5: G<any, any>; // Ok
  13. var v6: G<any>; // Error, wrong number of arguments
  14. var v7: G; // Error, no arguments

A type argument is simply a Type and may itself be a type reference to a generic type, as demonstrated by ‘v4’ in the example above.

As described in section 3.7, a type reference to a generic type G designates a type wherein all occurrences of G‘s type parameters have been replaced with the actual type arguments supplied in the type reference. For example, the declaration of ‘v1’ above is equivalent to:

  1. var v1: {
  2. x: { a: string; }
  3. y: { a: string; b: string; c: string };
  4. };

3.8.3 Object Type Literals

An object type literal defines an object type by specifying the set of members that are statically considered to be present in instances of the type. Object type literals can be given names using interface declarations but are otherwise anonymous.

  ObjectType:   {TypeBodyopt}

  TypeBody:   TypeMemberList;opt   TypeMemberList,opt

  TypeMemberList:   TypeMember   TypeMemberList;TypeMember   TypeMemberList,TypeMember

  TypeMember:   PropertySignature   CallSignature   ConstructSignature   IndexSignature   MethodSignature

The members of an object type literal are specified as a combination of property, call, construct, index, and method signatures. Object type members are described in section 3.9.

3.8.4 Array Type Literals

An array type literal is written as an element type followed by an open and close square bracket.

  ArrayType:   PrimaryType[no LineTerminator here][]

An array type literal references an array type (section 3.3.2) with the given element type. An array type literal is simply shorthand notation for a reference to the generic interface type ‘Array’ in the global namespace with the element type as a type argument.

When union, intersection, function, or constructor types are used as array element types they must be enclosed in parentheses. For example:

  1. (string | number)[]
  2. (() => string)[]

Alternatively, array types can be written using the ‘Array<T>’ notation. For example, the types above are equivalent to

  1. Array<string | number>
  2. Array<() => string>

3.8.5 Tuple Type Literals

A tuple type literal is written as a sequence of element types, separated by commas and enclosed in square brackets.

  TupleType:   [TupleElementTypes]

  TupleElementTypes:   TupleElementType   TupleElementTypes,TupleElementType

  TupleElementType:   Type

A tuple type literal references a tuple type (section 3.3.3).

3.8.6 Union Type Literals

A union type literal is written as a sequence of types separated by vertical bars.

  UnionType:   UnionOrIntersectionOrPrimaryType|IntersectionOrPrimaryType

A union type literal references a union type (section 3.4).

3.8.7 Intersection Type Literals

An intersection type literal is written as a sequence of types separated by ampersands.

  IntersectionType:   IntersectionOrPrimaryType&PrimaryType

An intersection type literal references an intersection type (section 3.5).

3.8.8 Function Type Literals

A function type literal specifies the type parameters, regular parameters, and return type of a call signature.

  FunctionType:   TypeParametersopt(ParameterListopt)=>Type

A function type literal is shorthand for an object type containing a single call signature. Specifically, a function type literal of the form

  1. < T1, T2, ... > ( p1, p2, ... ) => R

is exactly equivalent to the object type literal

  1. { < T1, T2, ... > ( p1, p2, ... ) : R }

Note that function types with multiple call or construct signatures cannot be written as function type literals but must instead be written as object type literals.

3.8.9 Constructor Type Literals

A constructor type literal specifies the type parameters, regular parameters, and return type of a construct signature.

  ConstructorType:   newTypeParametersopt(ParameterListopt)=>Type

A constructor type literal is shorthand for an object type containing a single construct signature. Specifically, a constructor type literal of the form

  1. new < T1, T2, ... > ( p1, p2, ... ) => R

is exactly equivalent to the object type literal

  1. { new < T1, T2, ... > ( p1, p2, ... ) : R }

Note that constructor types with multiple construct signatures cannot be written as constructor type literals but must instead be written as object type literals.

3.8.10 Type Queries

A type query obtains the type of an expression.

  TypeQuery:   typeofTypeQueryExpression

  TypeQueryExpression:   IdentifierReference   TypeQueryExpression.IdentifierName

A type query consists of the keyword typeof followed by an expression. The expression is restricted to a single identifier or a sequence of identifiers separated by periods. The expression is processed as an identifier expression (section 4.3) or property access expression (section 4.13), the widened type (section 3.12) of which becomes the result. Similar to other static typing constructs, type queries are erased from the generated JavaScript code and add no run-time overhead.

Type queries are useful for capturing anonymous types that are generated by various constructs such as object literals, function declarations, and namespace declarations. For example:

  1. var a = { x: 10, y: 20 };
  2. var b: typeof a;

Above, ‘b’ is given the same type as ‘a’, namely { x: number; y: number; }.

If a declaration includes a type annotation that references the entity being declared through a circular path of type queries or type references containing type queries, the resulting type is the Any type. For example, all of the following variables are given the type Any:

  1. var c: typeof c;
  2. var d: typeof e;
  3. var e: typeof d;
  4. var f: Array<typeof f>;

However, if a circular path of type queries includes at least one ObjectType, FunctionType or ConstructorType, the construct denotes a recursive type:

  1. var g: { x: typeof g; };
  2. var h: () => typeof h;

Here, ‘g’ and ‘g.x’ have the same recursive type, and likewise ‘h’ and ‘h()’ have the same recursive type.

3.8.11 This-Type References

The this keyword is used to reference the this-type (section 3.6.3) of a class or interface.

  ThisType:   this

The meaning of a ThisType depends on the closest enclosing FunctionDeclaration, FunctionExpression, PropertyDefinition, ClassElement, or TypeMember, known as the root declaration of the ThisType, as follows:

  • When the root declaration is an instance member or constructor of a class, the ThisType references the this-type of that class.
  • When the root declaration is a member of an interface type, the ThisType references the this-type of that interface.
  • Otherwise, the ThisType is an error.

Note that in order to avoid ambiguities it is not possible to reference the this-type of a class or interface in a nested object type literal. In the example

  1. interface ListItem {
  2. getHead(): this;
  3. getTail(): this;
  4. getHeadAndTail(): { head: this, tail: this }; // Error
  5. }

the this references on the last line are in error because their root declarations are not members of a class or interface. The recommended way to reference the this-type of an outer class or interface in an object type literal is to declare an intermediate generic type and pass this as a type argument. For example:

  1. type HeadAndTail<T> = { head: T, tail: T };
  2. interface ListItem {
  3. getHead(): this;
  4. getTail(): this;
  5. getHeadAndTail(): HeadAndTail<this>;
  6. }