TypeScript entry-advanced type, typescript entry type

Source: Internet
Author: User

TypeScript entry-advanced type, typescript entry type
Advanced Type

 

Crossover type

The cross type is to combine multiple types into a new type. The new type has members of these types, and all the features of these types are their complexes, like the Union of a set

Example:

function extend<T,U>(first: T, second: U): T&U {    let result = <T & U>{};    for (let id in first) {        (<any>result)[id] = first[id];    }    for (let id in second) {        if (!result.hasOwnProperty(id)) {            (<any>result)[id] = second[id];        }    }    return result;}class Person {    constructor(public name: string) {    }}interface Loggable {    log(): void;}class myLoggable implements Loggable {    log() {        console.log('qwe');    }}let jim = extend(new Person('qq'), new myLoggable());console.log(jim.name);jim.log();

In this example, jim has the name attribute in Person and the log () method in myLoggable.

 

Union type

Union type. It is not like that the cross type is a collection of multiple types. It indicates that it is one of these types, such as the intersection in the set, only features of multiple types can be called.

For example, to pass a parameter to a function, the parameter may be number or string.

function padLeft(value: string, padding: any) {    if (typeof padding === "number") {        return Array(padding + 1).join(" ") + value;    }    if (typeof padding === "string") {        return padding + value;    }    throw new Error(`Expected string or number, got '${padding}'.`);}padLeft("Hello world", 4); // "    Hello world"

There is a problem here. Defining padding as any indicates that we can pass any value to padding. This error is not reported by TypeScript and will only be reported during compilation.

 

To solve this problem, you can use the Union type and use vertical bars to separate each type, indicating that it is one of these types.

function padLeft(value: string, padding: string | number) {    ........}let f = padLeft("Hello world", true); // error

 

If a value is of the Union type, only members of these types can be accessed.

interface Bird {    fly();    layEggs();}interface Fish {    swim();    layEggs();}function getSmallPet(): Fish | Bird {    ...}let pet = getSmallPet();pet.layEggs(); // okaypet.swim();    // errors

The return type of getSmallPet is a union type, so pet can only access the member layEggs () of Bird and Fish ()

In the above example, we do not know the type of pet, so it is impossible to access which are not public members. If we know the type of pet, you can access all members of this type.

 

Type Protection and differentiated types

To solve the problem of determining the specific types mentioned above, type assertions (type conversion) need to be introduced)

let pet = getSmallPet();if ((<Fish>pet).swim) {    (<Fish>pet).swim();} else {    (<Bird>pet).fly();}

The problem is obvious. It is troublesome to convert the type of pet every time.

 

User-Defined Type Protection

Type Protection can solve the shortcomings of the above Type assertions every time. Type Protection is some expressions that check at runtime to ensure the type in a specific scope. To define a Type Protection, we just need to define a function, and its return value is a type asserted.

function isFish(pet: Fish | Bird): pet is Fish {    return (<Fish>pet).swim !== undefined;}

 

Pet is Fish is a type assertion. An asserted is in the form of parameterName is Type. parameterName must be a parameter name from the current function signature.

// There is no problem with the call of 'swim 'and 'fly'. if (isFish (pet) {pet. swim () ;}else {pet. fly ();}

TypeScript not only knows that it is Fish in if, but also knows that it is Bird in else.

 

Typeof Type Protection

We can use the previous padLeft code to implement the type assertion.

function isNumber(x: any): x is number {    return typeof x === "number";}function isString(x: any): x is string {    return typeof x === "string";}function padLeft(value: string, padding: string | number) {    if (isNumber(padding)) {        return Array(padding + 1).join(" ") + value;    }    if (isString(padding)) {        return padding + value;    }    throw new Error(`Expected string or number, got '${padding}'.`);}

 

If you want to write in this way, you need to write a function for each original type, which is troublesome. TypeScript will set "typeof v = typeofname" and "typeof v! = Typeofname "is treated as type protection, so you don't have to write a function for an original type. You can simply use typeof.

function padLeft(value: string, padding: string | number) {    if (typeof padding === "number") {        return Array(padding + 1).join(" ") + value;    }    if (typeof padding === "string") {        return padding + value;    }    throw new Error(`Expected string or number, got '${padding}'.`);}

 

Instanceof Type Protection

Instanceof Type Protection is a way to refine types through Constructors

Interface Padder {getPaddingString (): string} class SpaceRepeatingPadder implements Padder {constructor (private numSpaces: number) {} getPaddingString () {return Array (this. numSpaces + 1 ). join ("") ;}} class StringPadder implements Padder {constructor (private value: string) {}getpaddingstring () {return this. value ;}} function getRandomPadder () {return Math. random () <0.5? New Round (4): new StringPadder ("");} // type: Round | StringPadderlet padder: Padder = getRandomPadder (); if (padder instanceof SpaceRepeatingPadder) {padder; // Type Details: 'spacerepeatingpadder'} if (padder instanceof StringPadder) {padder; // Type Details: 'stringpadder '}

 

Type alias

A type alias is an alias for a type and can be used for basic data types.

type Name = string;type NameResolver = () => string;type NameOrResolver = Name | NameResolver;function getName(n: NameOrResolver): Name {    if (typeof n === 'string') {        return n;    }    else {        return n();    }}

 

Different from the interface, the type alias does not create a new type, but the type name has changed.

type Alias = { num: number }interface Interface {    num: number;}declare function aliased(arg: Alias): Alias;declare function interfaced(arg: Interface): Interface;

In the above Code, The interfaced return value type is Interface, while the aliased return value type is the object literal

Another difference between the type alias and the interface is that the type alias cannot be extends or implements

The two differences between the type alias and the interface are also the same, that is, generic type can be used.

type Tree<T> = {    value: T;    left: Tree<T>;    right: Tree<T>;}

 

String Literal type

The string literal type can work well with the union type, type protection, and type alias.

type Easing = "ease-in" | "ease-out" | "ease-in-out";class UIElement {    animate(dx: number, dy: number, easing: Easing) {        if (easing === "ease-in") {            // ...        }        else if (easing === "ease-out") {        }        else if (easing === "ease-in-out") {        }        else {            // error! should not pass null or undefined.        }    }}let button = new UIElement();button.animate(0, 0, "ease-in");button.animate(0, 0, "uneasy"); // error: "uneasy" is not allowed here

You can only select one of the three specified types for transfer. If you select another type, an error is returned.

 

Identifiable Federation

The string literal type, union type, type protection, and type alias can be merged to create an advanced mode called recognizable union.

First, define three interfaces to be joined. Each interface has a kind attribute, but the value is different. The king attribute can be used as an identifiable feature and identifier.

interface Square {    kind: "square";    size: number;}interface Rectangle {    kind: "rectangle";    width: number;    height: number;}interface Circle {    kind: "circle";    radius: number;}

 

Then combine them.

type Shape = Square | Rectangle | Circle;

 

Use identifiable Federation

function area(s: Shape) {    switch (s.kind) {        case "square": return s.size * s.size;        case "rectangle": return s.height * s.width;        case "circle": return Math.PI * s.radius ** 2;    }}

 

Note: If you add a new type to the Shape, you must add the corresponding judgment under the switch.

 

References:

TypeScript: the superset of JavaScript

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.