fluent-accessor
    TypeScript icon, indicating that this package has built-in type declarations

    1.2.3 • Public • Published

    Actions Status Actions Status Actions Status Test Coverage Maintainability Packages npm version

    Dynamically creates an accessor function based on property paths!

    How to use it

    Just use $ to starts the navigation:

    const func = $<MyType>().field1.field2.field3[0].field4;

    func will be an accessor for the field4 following the whole specified path

    console.log(func(myInstance)); // returns the value of myInstance.field1.field2.field3[0].field4;

    You can also run it with a fallback

    console.log(func(myInstance, null)); // In case of some property not existing, it will return null;

    If you want to return undefined instead, you also can, setting off the strictness of the function:

    setStrictness(func, false);
    console.log(func(myInstance)); // In case of some property not existing, it will return undefined;

    You can aplly fallback for a func implicitly

    applyFallback(field4, 123);
    console.log(func(myInstance)); // In case of some property not existing, it will return 123;

    You can retrieve the navigated properties

    const func = jsonPath(func); // return an iterable that yields 'field1', 'field2', 'field3', '0' and, then, 'field4'

    Finally, using TypeScript, let's suppose you have a function like this:

    function doStuff(field: (a: MyType) => T) {
      // do some stuff
    }

    Typescript can infer the generic types if you call it like this:

    const result = doStuff($('field1', 'field2'));

    This last option, combined with TypeScript, is very powerful! Because of contextual typing, you can infer each property to navigate without informing any type! Of course, if you didn't use "any" in your parameters ;)

    But why?

    You my ask yourself why would you do all this work if you can simply create an expression like this directly:

    const func = (x) => x.field1.field2.field3[0].field4;

    The reasons are: information and IDE helping. Using fluent-accessor you can have more than just a function that returns the value of a nested field:

    • You can know the path you're accessing just by using jsonPath;
    • You have control of scope: you know that the generated expression will only return the field value;
    • You can have auto-complete while programming even though you're not dealing with the said object;
    • You can compose the expression to access the nested property dynamically;

    Some possible applications

    Imagine you have a object like this:

    interface Nested {
      nestedFoo: MyPOCO;
      bar: string;
    }
    
    interface MyPOCO {
      foo: Nested;
      bar: string;
    }

    And you want to create a function that sorts an array by a nested field. Let's say the first implementation you just use a string to do it:

    function mySort<T>(arr: T, fields: string);
    
    // Usage
    mySort(myPOCOArray, 'foo.nestedfoo.foo.nestedFoo.bar');

    That's can work, but because the lack of IDE auto-complete and lint helping, you may let a typo pass, like in the example above. Let's try with an array:

    function mySort<T>(arr: T, fields: Array<T[keyof T]>);
    
    // Usage
    mySort(myPOCOArray, ['foo', 'nestedFoo', 'foo', 'nestedFoo', 'bar']);

    Well, that actually will not compile because of the type you specified for the array. You can use string, but then, you'll have the same problem of the first approach. Now, let's try with fluent-accessor

    function mySort<T>(arr: T, fields: Expression<T, unknown>);
    
    // Usage
    mySort(myPOCOArray, $('foo', 'nestedFoo', 'foo', 'nestedFoo', 'bar'));

    Now you have it. You have a strong typed function which will help you to not typo over your implementation.

    Also, internally, you have access to all the nested field names you'll consider in your index because, I don't know, you want to register it in some place.

    get and getOrDef

    You can also use this library to get directly the value of a nested property, like this:

    const result = get(myInstance, 'foo', 'bar', '0', 'fooBar');

    The advantage of it? result is strongly typed by default! In this call, if the nested path is not found, result will be undefined. If you want to define a default value for it, use getOrDef

    const result = getOrDef(myInstance, 99, 'foo', 'bar', '0', 'fooBar');

    Special symbols

    Let's assume that, in the example above, nestedFoo is a number. The accessor generated by $ will return the triple of it! You also have some custom built in mappers, like:

    someFunc($('foo', 'nestedFoo', 'foo', 'nestedFoo', baseOp.first);
    someFunc($('foo', 'nestedFoo', 'foo', 'nestedFoo', baseOp.last);

    In the examples above, nestedFoo need to be an iterable, otherwise the typing will throw an error.

    License

    Licensed under MIT.

    Install

    npm i fluent-accessor

    DownloadsWeekly Downloads

    0

    Version

    1.2.3

    License

    MIT

    Unpacked Size

    43.8 kB

    Total Files

    54

    Last publish

    Collaborators

    • avatar
    • avatar
    • avatar
    • avatar
    • avatar
    • avatar