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:
(string | number)[]
((x: string) => string) | ((x: number) => number)
(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:
interface A { a: string; }
interface B extends A { b: string; }
interface C extends B { c: string; }
interface G<T, U extends B> {
x: T;
y: U;
}
var v1: G<A, C>; // Ok
var v2: G<{ a: string }, C>; // Ok, equivalent to G<A, C>
var v3: G<A, A>; // Error, A not valid argument for U
var v4: G<G<A, B>, C>; // Ok
var v5: G<any, any>; // Ok
var v6: G<any>; // Error, wrong number of arguments
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:
var v1: {
x: { a: string; }
y: { a: string; b: string; c: string };
};
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:
(string | number)[]
(() => string)[]
Alternatively, array types can be written using the ‘Array<T>’ notation. For example, the types above are equivalent to
Array<string | number>
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
< T1, T2, ... > ( p1, p2, ... ) => R
is exactly equivalent to the object type literal
{ < 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: new
TypeParametersopt (
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
new < T1, T2, ... > ( p1, p2, ... ) => R
is exactly equivalent to the object type literal
{ 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: typeof
TypeQueryExpression
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:
var a = { x: 10, y: 20 };
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:
var c: typeof c;
var d: typeof e;
var e: typeof d;
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:
var g: { x: typeof g; };
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
interface ListItem {
getHead(): this;
getTail(): this;
getHeadAndTail(): { head: this, tail: this }; // Error
}
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:
type HeadAndTail<T> = { head: T, tail: T };
interface ListItem {
getHead(): this;
getTail(): this;
getHeadAndTail(): HeadAndTail<this>;
}