TypeScript Objects as Dictionary types as in C#

前端 未结 6 716
春和景丽
春和景丽 2020-11-27 09:39

I have some JavaScript code that uses objects as dictionaries; for example a \'person\' object will hold a some personal details keyed off the email address.



        
相关标签:
6条回答
  • 2020-11-27 09:55

    You can use Record for this:

    https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkt

    Example (A mapping between AppointmentStatus enum and some meta data):

      const iconMapping: Record<AppointmentStatus, Icon> = {
        [AppointmentStatus.Failed]: { Name: 'calendar times', Color: 'red' },
        [AppointmentStatus.Canceled]: { Name: 'calendar times outline', Color: 'red' },
        [AppointmentStatus.Confirmed]: { Name: 'calendar check outline', Color: 'green' },
        [AppointmentStatus.Requested]: { Name: 'calendar alternate outline', Color: 'orange' },
        [AppointmentStatus.None]: { Name: 'calendar outline', Color: 'blue' }
      }
    

    Now with interface as value:

    interface Icon { Name: string Color: string }

    Usage:

    const icon: SemanticIcon = iconMapping[appointment.Status]

    0 讨论(0)
  • 2020-11-27 09:57

    In newer versions of typescript you can use:

    type Customers = Record<string, Customer>
    

    In older versions you can use:

    var map: { [email: string]: Customer; } = { };
    map['foo@gmail.com'] = new Customer(); // OK
    map[14] = new Customer(); // Not OK, 14 is not a string
    map['bar@hotmail.com'] = 'x'; // Not OK, 'x' is not a customer
    

    You can also make an interface if you don't want to type that whole type annotation out every time:

    interface StringToCustomerMap {
        [email: string]: Customer;
    }
    
    var map: StringToCustomerMap = { };
    // Equivalent to first line of above
    
    0 讨论(0)
  • 2020-11-27 09:59

    You can use templated interfaces like this:

    interface Map<T> {
        [K: string]: T;
    }
    
    let dict: Map<number> = {};
    dict["one"] = 1;
    
    0 讨论(0)
  • 2020-11-27 10:01

    You can also use the Record type in typescript :

    export interface nameInterface { 
        propName : Record<string, otherComplexInterface> 
    }
    
    0 讨论(0)
  • 2020-11-27 10:01

    Lodash has a simple Dictionary implementation and has good TypeScript support

    Install Lodash:

    npm install lodash @types/lodash --save
    

    Import and usage:

    import { Dictionary } from "lodash";
    let properties : Dictionary<string> = {
        "key": "value"        
    }
    console.log(properties["key"])
    
    0 讨论(0)
  • 2020-11-27 10:06

    In addition to using an map-like object, there has been an actual Map object for some time now, which is available in TypeScript when compiling to ES6, or when using a polyfill with the ES6 type-definitions:

    let people = new Map<string, Person>();
    

    It supports the same functionality as Object, and more, with a slightly different syntax:

    // Adding an item (a key-value pair):
    people.set("John", { firstName: "John", lastName: "Doe" });
    
    // Checking for the presence of a key:
    people.has("John"); // true
    
    // Retrieving a value by a key:
    people.get("John").lastName; // "Doe"
    
    // Deleting an item by a key:
    people.delete("John");
    

    This alone has several advantages over using a map-like object, such as:

    • Support for non-string based keys, e.g. numbers or objects, neither of which are supported by Object (no, Object does not support numbers, it converts them to strings)
    • Less room for errors when not using --noImplicitAny, as a Map always has a key type and a value type, whereas an object might not have an index-signature
    • The functionality of adding/removing items (key-value pairs) is optimized for the task, unlike creating properties on an Object

    Additionally, a Map object provides a more powerful and elegant API for common tasks, most of which are not available through simple Objects without hacking together helper functions (although some of these require a full ES6 iterator/iterable polyfill for ES5 targets or below):

    // Iterate over Map entries:
    people.forEach((person, key) => ...);
    
    // Clear the Map:
    people.clear();
    
    // Get Map size:
    people.size;
    
    // Extract keys into array (in insertion order):
    let keys = Array.from(people.keys());
    
    // Extract values into array (in insertion order):
    let values = Array.from(people.values());
    
    0 讨论(0)
提交回复
热议问题