0

With TypeScript ~3.1.6, I have declared this interface:

export interface Shop {
  readonly displayName: string;
  name: string;
  city: string;
}

where displayName is set by the backend and cannot be changed by the UI.

I created the following Service to create a new Shop, the REST for which takes city and name as properties:

createShop = (shop: Partial<Shop>) =>
  this._http.post(`/shop/new`, shop, this._options)
    .pipe(
      catchError(this.handleError)
    );

And I pass data (from an Angular 7 reactive form) thusly:

createShop = () =>
  this._shopService.createShop({
    name: this.form.get('name').value,
    city: this.form.get('city').value
  }).subscribe(/* handlers */);

I've declared the create method's shop as a Partial<Shop> because I don't want to maintain a separate <CreateShop> interface, and I thought this was precisely what Partial<T>s were for.

Yet, I still get this error at compilation:

src/app/addShop.component.ts(39,40): error TS2345: Argument of type '{ name: string; city: string; }' is not assignable to parameter of type 'Shop'.
  Property 'displayName' is missing in type '{ name: string; city: string; }'.

If I declare a

export interface CreateShop extends Partial<Shop> {}

and use that instead of Partial<Shop> it compiled.

Why can't I use the inline Partial declaration?

Especially as that seems to go exactly against Partial<T> only works with inline values

msanford
  • 11,803
  • 11
  • 66
  • 93
  • 1
    Can you post more of your code, specifically the subscription handlers? The error message you're getting doesn't seem to be related to `Partials`. That error would be more along the lines of `Property 'displayName' is optional in type 'Partial' but required in type 'Shop'`. I would guess that this compilation error is related to somewhere where you're trying to assign an implicitly typed return object to a value of type `Shop`, and could be solved with explicit typing. – joh04667 Dec 12 '18 at 18:31
  • 2
    I created similar code in typescript playground, and it seemed to be working fine. the version of ts there is 3.2 So can you first try 3.2 to narrow down the issue? – ABOS Dec 12 '18 at 18:32
  • 1
    I would expect this to work, no bug this big could slip through in a Typescript release. The error suggests that the type that is assigned to is `Shop` not `Partial` maybe something else is happening in your code. – Titian Cernicova-Dragomir Dec 12 '18 at 18:46
  • @joh04667 Hi! The subscription handlers actually do nothing with the `shop`, which is why I didn't post them: they merely use the `next` and `error` handlers - without values - to display UI success/error banners. The second part of your comment I think is _precisely_ what's happening. – msanford Dec 12 '18 at 20:26
  • @ABOS Sadly, I cannot: `ERROR in The Angular Compiler requires TypeScript >=3.1.1 and <3.2.0 but 3.2.2 was found instead.` – msanford Dec 12 '18 at 20:26
  • @TitianCernicova-Dragomir I agree, and similar uses of `Partial` elsewhere in my code seem to work fine. The problem must indeed be my code somehow. I'll keep digging. – msanford Dec 12 '18 at 20:28
  • Please join me in closing this question: restarting the terminal shell in which I was building cleared the problem without having changed _any_ code. `¯\_(ツ)_/¯` Or should I just delete it. Opinions? – msanford Dec 12 '18 at 20:57
  • 1
    haha, whenever odd issues happened in the project I worked on, the first thing I did was to restart the build process... The fixed most counter-intuitive issues. – ABOS Dec 12 '18 at 21:47
  • @ABOS Oh, I did. I was using angular's (webpack's) hot module reload, then killed that, then tried a fresh build, cleaned, build in prod mode//. What fixed it was closing the _linux shell_ that the builds were running in. Never had that problem before... – msanford Dec 13 '18 at 13:43

1 Answers1

2

You can overcome this issue by casting the object literal to Shop

createShop = () =>
  this._shopService.createShop({
    name: this.form.get('name').value,
    city: this.form.get('city').value
  } as Shop).subscribe(/* handlers */);