简体   繁体   中英

Typescript: Problem with generic Parameter/ReturnType and string Enums

I currently try to add proper typings to the following simplified function:

getProperty(property:string):any

My goal is to make it possible to pass the property parameter as string or string enum and get the correct return type for it.

For that I have created a new string enum Property:

enum Property {
    ENABLED = 'enabled',
    SIZE    = 'size'
}

a generic type PropertyType:

type PropertyType < T > =
    T extends Property.ENABLED ? boolean :
    T extends Property.SIZE    ? number  : any;

and changed the function signature to:

getProperty<T extends Property>(property : T) : PropertyType<T>

This works perfect if I call the function with the new string enum :

const enabled: boolean = getProperty(Property.ENABLED);

But if I call the function with a simple string (needed for backward compatibility) like that:

const enabled: boolean = getProperty("enabled");

I get the following error:

Argument of type '"enabled"' is not assignable to parameter of type 'Property'.(2345)

Is there any good way to support both ways ( string & string enum ) to pass the property parameter?

My example is also available here: Typescript Playground

You can either overload the function or make the type parameter of getProperty a union type.

Overload:

function getProperty(property: string): any;
function getProperty<T extends Property>(property : T) : PropertyType<T>
{
    return store[property];
}

Union Type:

function getProperty<T extends Property | string>(property : T) : PropertyType<T>
{
    return store[property];
}

Full code:

//Example Value store
const store: { [key: string]: any } = {
    "enabled": true,
    "size": 4
};

//--------------------------------------------------------------------------

//String Enum Property
enum Property {
    ENABLED = 'enabled',
    SIZE    = 'size'
}

//--------------------------------------------------------------------------

//Property Types
type PropertyType < T > =
T extends Property.ENABLED ? boolean :
T extends Property.SIZE    ? number  : any;

//--------------------------------------------------------------------------

// Generic getProperty function
 function getProperty<T extends Property | string>(property : T) : PropertyType<T>
    {
        return store[property];
    }

//--------------------------------------------------------------------------

const enabled0: boolean = getProperty(Property.ENABLED);
const enabled1: boolean = getProperty('enabled');

Another way is to just simply choose a different function name, since you don't gain any type safety from overloading. Imo this is a better option to stay backwards compatible.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM