I have one function selectProperties
to select the key value from some interface and get the error error TS2322: Type 'keyof T' is not assignable to type 'T'.
after upgrading to typescript 4.4.
typescript playground, anyone have better idea how I can walk around?
export interface QueryActioned {
event: string;
properties:string
}
export interface QueryStarted {
event: number
properties: number
}
export type QueryProps = Partial<(QueryActioned & QueryStarted)['properties']>;
const selectProperties = <T extends Partial<QueryProps>>(
keys: (keyof T)[],
properties: T
): T => {
const defaultVal: T = {} as T;
return (Object.keys(properties) as (keyof T)[])
.filter((key) => keys.includes(key))
.reduce(
(acc, key) => ({
...acc,
[key]: properties[key],
}),
defaultVal
);
};
CodePudding user response:
Looks like that you are expecting reduce to return an object of type T, when it only accepts a default value that matches the type of the array value it is iterating over, and ultimately returns some combination of the values. Reduce will only end up returning a single value from the keys of T.
If you are selecting some of the keys of type T, you cannot have T as your return type. You are infact creating a Partial type based on the list of given keys.
You can return that by using forEach and mutating a return object.
export interface QueryActioned {
event: string;
properties:string
}
export interface QueryStarted {
event: number
properties: number
}
export type QueryProps = Partial<(QueryActioned & QueryStarted)['properties']>;
const selectProperties = <T extends Partial<QueryProps>>(
keys: (keyof T)[],
properties: T
) => {
const defaultVal: Partial<T> = {};
Object.keys(properties)
.filter(key => keys.includes(key))
.forEach(key => {defaultVal[key as keyof T] = properties[key]});
return defaultVal
};
If you actually want to get the values from the selected keys on T, then you can use map instead...
export interface QueryActioned {
event: string;
properties:string
}
export interface QueryStarted {
event: number
properties: number
}
export type QueryProps = Partial<(QueryActioned & QueryStarted)['properties']>;
const selectProperties = <T extends Partial<QueryProps>>(
keys: (keyof T)[],
properties: T
): (T[keyof T])[] => {
return Object.keys(properties)
.filter(key => keys.includes(key))
.map(key => properties[key]);
};
Either way, reduce will combine all the values in the keyof T array, and you specified your return type as T which would be where the error comes from.