Tagged union types
TypeScript 2.0 implements support for tagged (or discriminated) union types.Specifically, the TS compiler now support type guards that narrow union types based on tests of a discriminant property and furthermore extend that capability to switch
statements.
Example
interface Square {
kind: "square";
size: number;
}
interface Rectangle {
kind: "rectangle";
width: number;
height: number;
}
interface Circle {
kind: "circle";
radius: number;
}
type Shape = Square | Rectangle | Circle;
function area(s: Shape) {
// In the following switch statement, the type of s is narrowed in each case clause
// according to the value of the discriminant property, thus allowing the other properties
// of that variant to be accessed without a type assertion.
switch (s.kind) {
case "square": return s.size * s.size;
case "rectangle": return s.width * s.height;
case "circle": return Math.PI * s.radius * s.radius;
}
}
function test1(s: Shape) {
if (s.kind === "square") {
s; // Square
}
else {
s; // Rectangle | Circle
}
}
function test2(s: Shape) {
if (s.kind === "square" || s.kind === "rectangle") {
return;
}
s; // Circle
}
A discriminant property type guard is an expression of the form x.p == v
, x.p === v
, x.p != v
, or x.p !== v
, where p
and v
are a property and an expression of a string literal type or a union of string literal types.The discriminant property type guard narrows the type of x
to those constituent types of x
that have a discriminant property p
with one of the possible values of v
.
Note that we currently only support discriminant properties of string literal types.We intend to later add support for boolean and numeric literal types.