Is there a way to extract nested types from object, based on strings in array in typescript

Християн Христов

I'm trying to create a typed comparator function with type safety so that I'm sure that I'm always sorting with existing values So far I have done the following:

export enum SortDirection {
    ASCENDING = "ASCENDING",
    DESCENDING = "DESCENDING",
}

/**
 * Sorts in place Array of objects
 * @param path path to numeric value
 * @param direction the way that numeric values will be evaluated
 * @returns the sorted array
 */
export const sortByNumeric = <T>(path: Array<keyof T>, direction = SortDirection.ASCENDING) => <K extends Record<keyof T, any>>(current: K, next: K) => {
    const extractedA = +path.reduce((acc, k) => acc[k], current);
    const extractedB = +path.reduce((acc, k) => acc[k], next);
    return direction === SortDirection.ASCENDING ? extractedA - extractedB : extractedB - extractedA;
}

let source = [
    {
        name: 'Jon',
        age: 20,
        father: {
            name: 'Jon Senior',
            age: 60,
            otherProp: 100
        }
    },
    {
        name: 'Gabriel',
        age: 25,
        father: {
            name: 'Jon Senior',
            age: 80,
            otherProp: 20
        }
    }
];
source.sort(sortByNumeric(['age']));

The function is working fine with a single property, but it is not able to work with nested paths like so :

source.sort(sortByNumeric(['father' , 'otherProp']));
// Here this will throw an error that the prop doesn't exits, while this is actually a valid property

or

source.sort(sortByNumeric(['age' , 'father']));
// Here there will be no error, while at the same time this is invalid value as there is no key for the 'father'

I'm sure that I'm doing something wrong with the generics, but I have no idea how and what to fix here, any guidance will be appreciated.

KSab

It's possible, but not simple to type arbitrarily nested keys. It depends on how exactly you want the type to behave but a possible implementation of such a type would be:

export type NumericKeyPath<T> =
    [T] extends [number] ? []
    : [T] extends [object] ? NumericKeyPathProperty<T, keyof T>
    : never;

type NumericKeyPathProperty<T, Key extends keyof T> =
    Key extends (string | number) ? [ Key, ...NumericKeyPath<T[Key]> ]
    : never;

type Test = NumericKeyPath<{ name: string; age: number; father: { name: string; age: number; otherProp: number } }>;
// type Test = ["age"] | ["father", "age"] | ["father", "otherProp"]

Used with your comparator function:

export const sortByNumeric = <T>(path: NumericKeyPath<T>, direction = SortDirection.ASCENDING) => (current: T, next: T) => {
    // the below casts could be done more precisely 
    const extractedA = +(path as string[]).reduce((acc: any, k) => acc[k], current);
    const extractedB = +(path as string[]).reduce((acc: any, k) => acc[k], next);
    return direction === SortDirection.ASCENDING ? extractedA - extractedB : extractedB - extractedA;
}

let source = [
    {
        name: 'Jon',
        age: 20,
        father: {
            name: 'Jon Senior',
            age: 60,
            otherProp: 100
        }
    },
    {
        name: 'Gabriel',
        age: 25,
        father: {
            name: 'Jon Senior',
            age: 80,
            otherProp: 20
        }
    }
];

source.sort(sortByNumeric(['age']));
// Works

source.sort(sortByNumeric(['father' , 'otherProp']));
// Works

source.sort(sortByNumeric(['age' , 'father']));
// Error

Playground link

Note that since it seemed to be the intention of the function, I wrote NumericKeyPath to only permit paths to numeric values. The relevant line is [T] extends [number] ? [], for example if you would like to permit string values as well you could change this to [T] extends [number | string] ? [].

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

How can I obtain the correct types for an array or object based on an array of object nested keys with generics in typescript?

From Dev

TypeScript types from array to object

From Dev

Extract typescript types from function to Object

From Dev

Typescript - Create an object based on nested array values

From Dev

Extract data from Nested Array Object

From Dev

Creating a nested Javascript Object from an array of Strings

From Dev

How to get array of strings from nested object

From Dev

Extract sub-object from nested object typescript

From Dev

Nested object from an array using lodash in typescript

From Dev

Filtering item from nested object array in typescript

From Dev

How to extract exact union type from object key strings in typescript?

From Dev

TypeScript - extract nested property from all properties in object

From Dev

Extract array values as Typescript types

From Dev

TypeScript types for heavily nested object

From Dev

How to extract a specific substring (based on regex) from an array of strings

From Dev

How to extract an array from an object with property and array in typescript?

From Dev

How to extract a particular element from an object based on key in typescript

From Dev

How to convert typescript types of strings to array of strings?

From Dev

How to extract values from an object and return it in an array of strings with specific requirements

From Dev

Remove object from nested array if array is empty in Typescript

From Dev

Query to extract ids from a deeply nested json array object in Presto

From Dev

How do I extract a specific object from a nested array?

From Dev

Extract a key/value object type from the properties of an array of objects in Typescript

From Dev

Derive keys from strings in array in typescript to define object property names

From Dev

Cannot access nested property from an array of object TypeScript

From Dev

Typescript extract type of nested object in template type

From Dev

Typescript - Narrowing union types for nested object props

From Dev

Inferring types of deeply nested object in Typescript

From Dev

How to declare nested object types safely in typescript

Related Related

  1. 1

    How can I obtain the correct types for an array or object based on an array of object nested keys with generics in typescript?

  2. 2

    TypeScript types from array to object

  3. 3

    Extract typescript types from function to Object

  4. 4

    Typescript - Create an object based on nested array values

  5. 5

    Extract data from Nested Array Object

  6. 6

    Creating a nested Javascript Object from an array of Strings

  7. 7

    How to get array of strings from nested object

  8. 8

    Extract sub-object from nested object typescript

  9. 9

    Nested object from an array using lodash in typescript

  10. 10

    Filtering item from nested object array in typescript

  11. 11

    How to extract exact union type from object key strings in typescript?

  12. 12

    TypeScript - extract nested property from all properties in object

  13. 13

    Extract array values as Typescript types

  14. 14

    TypeScript types for heavily nested object

  15. 15

    How to extract a specific substring (based on regex) from an array of strings

  16. 16

    How to extract an array from an object with property and array in typescript?

  17. 17

    How to extract a particular element from an object based on key in typescript

  18. 18

    How to convert typescript types of strings to array of strings?

  19. 19

    How to extract values from an object and return it in an array of strings with specific requirements

  20. 20

    Remove object from nested array if array is empty in Typescript

  21. 21

    Query to extract ids from a deeply nested json array object in Presto

  22. 22

    How do I extract a specific object from a nested array?

  23. 23

    Extract a key/value object type from the properties of an array of objects in Typescript

  24. 24

    Derive keys from strings in array in typescript to define object property names

  25. 25

    Cannot access nested property from an array of object TypeScript

  26. 26

    Typescript extract type of nested object in template type

  27. 27

    Typescript - Narrowing union types for nested object props

  28. 28

    Inferring types of deeply nested object in Typescript

  29. 29

    How to declare nested object types safely in typescript

HotTag

Archive