简体   繁体   中英

typescript cannot cast to generic type variable

I want to create a generic function to create actions in typescript-redux.

What I want is to use a function passing an interface as the type variable. So I'm starting with this function :

function action<F>(type: string, payload: any): F {
    return { type, payload };
}

I want To use it like this :

interface Login {
    type: LOGIN_REQUEST;
    payload: credentials;
}

const Login = (credentials: Credentials) 
     => action<Login>(LOGIN_REQUEST, credentials);

The problem is that is have this error :

Type '{ type: string; payload: any; }' is not assignable to type 'F'.

Since action is generic there really is no way for the compiler to know that the object literal { type: string; payload: any; } { type: string; payload: any; } { type: string; payload: any; } will satisfy the type F . This code would also be a valid call:

action<{ type: string; payload: any; otherMandatoryProp: boolean }>(LOGIN_REQUEST, credentials);

F in the above case has extra fields that action will not fill.

The simplest solution is to break out of the type safety sandbox in this case and use a type assertion:

function action<F>(type: string, payload: any): F {
    return { type, payload } as any;
}

This version would still allow a call with { type: string; payload: any; otherMandatoryProp: boolean } { type: string; payload: any; otherMandatoryProp: boolean } { type: string; payload: any; otherMandatoryProp: boolean } which may cause some people to make some assumptions about what fields are on the retuned object. If you want to restrict F to types with just type and payload you can use a type constraint that specifies that the properties type and payload exist on F and if any other properties exist they are of type never :

function action<F extends { type : string, payload : any} & { [P in Exclude<keyof F, 'type' | 'payload'>]: never }>(type: string, payload: any): F {
    return { type, payload } as any;
}
const Login = (credentials: credentials) => action<Login>(LOGIN_REQUEST, credentials);
action<{ type: string; payload: any; otherMandatoryProp: boolean }>(LOGIN_REQUEST, {}) // invalid call

The typescript return value should match the object that you are returning It Should be of type login( or you can set it to any)

function action<F>(type: string, payload: any): Login  {
    return { type, payload };
}

Because you won't return any value, but only Login , you need to add a constraint:

function action<F extends Login>(type: string, payload: any): F {
    return { type, payload } as F;
}

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