0
votes

I am trying to generalise a service layer in an API in typescript using a base Data Transfer Object.

To not have to re-write the types definition i'm using <Omit>. However, it raises some typescript errors that i am not able to understand.

For instance, i do not understand why the following code:

type A = { a: string };
function test<T extends A>(ot: Omit<T, "a">): T {
  return {
    ...ot,
    a: "a",
  };
}

is raising the following error:

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

I understand why

function test<T extends string>():T {return "This is not specific enough!"}

does not work, but in the case above we are just defining dynamically the omitted field, we are not forgetting any constraint. What am i getting wrong?

1
Is there a reason you prefer your version to something like this? - jcalz
That's a good workaround, however in my case the function is a member of a class and that generic is used in the class like this: class BaseService<Model> { function create(o: <Omit Model, "id">): Model now... maybe i could define my Model without the id everywhere and use your trick for all of the functions. It's just counter-intuitive - A. Laurent

1 Answers

1
votes

Your function fails type-checking because it is not type-safe. The error message explains: your function returns something which "is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'A'."

For example, type Foo = {a: 'foo'} is also a sub-type of the constraint A. If your function is called like test<Foo>(obj), then it promises to return something of type Foo, but the actual return value is not assignable to the type Foo.