简体   繁体   中英

Generic return type in object transformation

I have a function that accepts an object and returns a new one with additional properties. And I cannot figure out why this generic typing doesn't work.

const obj = { name: 'hello', id: 1 };

const transformObj = <T extends { name: string }>({ name, ...rest }: T): T & { newName: string } => ({
    name,
    newName: name + '1',
    ...rest,
});

Playground link

It returns this error

Type '{ name: string; newName: string; } & Pick<T, Exclude<keyof T, "name">>' is not assignable to type 'T & { newName: string; }'. Type '{ name: string; newName: string; } & Pick<T, Exclude<keyof T, "name">>' is not assignable to type 'T'. '{ name: string; newName: string; } & Pick<T, Exclude<keyof T, "name">>' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '{ name: string; }'.

Here's why it doesn't work as written. Notice the { newName: number } in obj . This object does meet the constraint <T extends { name: string }> , but trying to intersect it with { newName: string } creates a contradiction.

const obj = { name: 'hello', /**/ newName: 10 /**/, id: 1 };

This gives you the type you want, by removing "newName" from keyof rest with destructuring and then adding it back as a string .

const transformObj = <T extends { name: string, newName?: unknown }>({ name, newName, ...rest }: T): typeof rest & { name: string, newName: string } => ({
    ...rest,    
    name,
    newName: name + '1',
});

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