arbitrary type which could be unrelated, but types are related

Viewed 30

In this sample code:

function test<T>(param: T & {id: number}): T {
    const {id, ...rest} = param;
    return rest;
}

playground link

Typescript says that:

Type Omit<T & { id: number; }, "id"> is not assignable to type T.

T could be instantiated with an arbitrary type which could be unrelated to Omit<T & { id: number; }, "id">.(2322)

Wouldn't T and Omit<T & {id: number}, "id"> exactly the same type?

Maybe it's because we don't enforce that T holds an object:

function test<T extends Record<string, unknown>>(param: T & {id: number}): T {
    const {id, ...rest} = param;
    return rest;
}

that doesn't work either. The error is now:

Type Omit<T & { id: number; }, "id"> is not assignable to type T.

Omit<T & { id: number; }, "id"> is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Record<string, unknown>'.(2322)

I guess there's a case in which that wouldn't hold, if T did in fact had a field id. I've tried that too, but I couldn't find how to express to the compiler that constraint, that T cannot have an id field.

Can I type this function I'm trying to define, or somehow convince (without casts) typescript that this is correct? Obviously it would work i I started from T and returned Omit<T, 'id'>.. but I'm trying to type a more complex generic function which actually works on a type T but also receives items of type T & {id: number}.

1 Answers

I'm trying to type a more complex generic function which actually works on a type T but also receives items of type T & {id: number}

Would this suffice?

type WithID = { id: string; }

function test<T extends Partial<WithID>>(param: T): Omit<T, 'id'> {
    const {id, ...rest} = param;
    return rest;
}

const a = test({});
const b = test({ id: 'foo' });
const c = test({ id: 'foo', num: 42 });

playground

Related