'Dynamically access property with typecasting in TypeScript with generic

I have following simplified function that accept generic.

function filter<T>(data: T[]) {
    
    const filter = { field: 'name', type: 'string', condition: 'ct' }

    data.forEach((value) => {
    
        type DataPropertyValue = keyof typeof value
    
        // Following does not work 
        // const dynamicValue = (value[filter.field as DataPropertyValue] as String).toLowerCase() --- This does not work
        // const dynamicValue = value[filter.field as DataPropertyValue].toLowerCase() --- This does not work
    
        // But this works but I have to re-instantiate String here
        const dynamicValue = String(value[filter.field as DataPropertyValue]).toLowerCase()
        console.log(dynamicValue)
    })
}

This works but as you see I have to recreate instance of String to operate on the value. Is there anyway to do this without re-instantiating String again.



Solution 1:[1]

The problem is that value is of type T, which could be anything. Which means that the property you are trying to look up may not actually have a string type.

For example:

filter([{ name: true }])

Here T would be of type { name: boolean } and toLowerCase called on a boolean would throw an exception.


You could fix this by adding code that checks to make sure the value is the right runtime type before proceeding.

That might look something like this:

function filter<T>(data: T[]) {
    
    const filter = { field: 'name', type: 'string', condition: 'ct' }

    data.forEach((value) => {
        const dynamicValue = filter.field in value ? value[filter.field as keyof T] : undefined
        if (typeof dynamicValue === 'string') {
            console.log(dynamicValue.toLowerCase())
        } else {
            console.log('unsupported property type')
        }
    })
}

filter([{ name: true }]) // logs "unsupported property type"
filter([{ name: 'FOO' }]) // logs "foo"

I'm not sure if that's exactly what you after, but I think it's closer.

Playground

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Alex Wayne