Using of a discriminator for type identification

TypeScript is a structural language, which means that it does not rely on the name of the type like a nominal language. JavaScript doesn't have a type; hence, it is a structural language. C# or Java are both nominal languages. The difference is important because it means that TypeScript doesn't check for the name of the interface or type to take any decision. This makes sense when we think about how TypeScript compiles the code. During compilation, all types are stripped out of the code to produce a clean JavaScript. This symbiosis is in respect to JavaScript; thus, giving TypeScript the honor of being a superset of JavaScript. However, at runtime for TypeScript and design time for JavaScript, we need to know which type we are manipulating. In structural code, the approach is to analyze, compare, and infer type by looking at the structure. If specific members exist, it gives a hint of what we are working on. The following code example shows two identical interfaces with the same body, a type with the same structure as well, and the first variable with an anonymous type. The object can be of each type because it respects the contract of each one:

interface Type1 {
m1: string;
}
interface Type2 {
m1: string;
}
type Type3 = { m1: string };
const v0 = { m1: "AllTheSame" };
const v1: Type1 = v0;
const v2: Type2 = v0;
const v3: Type3 = v0;

In the previous example, the way to make every type different is with the concept of a discriminator. A discriminator is a member with a shared name between a group of a common type that needs to be distinguished. This group is often a union. The idea is to have a unique string literal per type with the same name. Having string literal as a type member requires the implementation to implement the same string. It means that each instance of a specific type will have the same string. TypeScript can then infer the type by looking at string literal. The following code example applies this principle. The common member is named kind, and each interface and type has a unique one. The anonymous type tries to impersonate Type1 but fails because the type inferred is a string and not a string literal:

interface Type1 {
kind: "Type1";
m1: string;
}

interface Type2 {
kind: "Type2";
m1: string;
}

type Type3 = { kind: "Type3"; m1: string };
const v0 = { kind: "Type1", m1: "AllTheSame" };
const v1: Type1 = v0; // Does not compile
const v2: Type2 = v0; // Does not compile
const v3: Type3 = v0; // Does not compile

The discriminator proves to be useful not only for avoid cross type but also for narrowing down a type. In a union of many types, when comparing against the discriminator, TypeScript will know exactly the type and hence the scope of the comparison. The following code allows reducing to the exact type. In that particular case, the m1 member is a member that is in all three types and thus does not require to be narrowed down to a single type to be used:

function threeLogic(param: Type1 | Type2 | Type3): void {
switch (param.kind) {
case "Type1":
console.log(param.m1); // param is type Type1
break;
case "Type2":
console.log(param.m1); // param is type Type2
break;
case "Type3":
console.log(param.m1); // param is type Type3
break;
}
}

If we have an interface with completely different members, the distinction is primordial to have access to a member that is unique to one interface or another. The following code narrows down the interface, allowing it to use a member from the proper type, depending on the comparison:

interface Alpha { kind: "Alpha", alpha: string }
interface Beta { kind: "Beta", beta: string }

function AlphaBeta(param: Alpha | Beta): void {
switch (param.kind) {
case "Alpha":
console.log(param.alpha);
break;
case "Beta":
console.log(param.beta);
break;
}
}

The usage of a string literal as a discriminator is often named the literal type guard or the tagged union. It is powerful for functional programming and provides a quick way to identify a type without having to develop specific conditions as needed in other techniques such as a user-defined guard.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.188.138