We work with an API that requires us to send off an object along with additional properties to tell it which properties on that object are to be modified by ading _X
and setting it to true
. For example if we had this object
{ firstName: 'Joe', lastName: 'Smith' }
and wanted to only change the lastName
property, we would send this:
{firstName: 'Joe', lastName: 'Smith', lastName_X: true }
I'd like to set up strong typing for this in TypeScript, but I seem to be missing something
type ApiBoolean<T extends object> = {
[index: `${K in keyof T}_X`]: true; // <== Error is here
};
function convertForApi<T extends object>(obj: T, keys: Array<keyof T>): ApiBoolean<T> {
const returnObj: ApiBoolean<T> = {...obj}
for(let k of keys){
returnObj[`${k}_X`] = true;
}
return returnObj;
}
const person = {
firstName: 'Joe',
lastName: 'Smith',
age: 35
};
const converted = convertForApi(person, ['lastName', 'age'])
I need to allow the indexer to have property suffixes. What am I doing wrong and how can I achieve this?
You could use an intersection of 2 mapped types:
type StringKeys<T extends object> = keyof {[K in keyof T as K extends string ? K : never]: unknown} & string;
type ApiBoolean<T extends object, KK extends StringKeys<T>[]> =
{[K in keyof T]: T[K]} &
{[K in KK[number] as `${K}_X`]: true} extends infer A ? A : never;
function convertForApi<T extends object, const K extends StringKeys<T>[]>(obj: T, keys: K) {
return keys.reduce((r, key) => (r[`${key}_X`] = true, r), {...obj} as any) as ApiBoolean<T, K>;
}