8000 feat: application service types default to any by vonagam · Pull Request #1566 · feathersjs/feathers · GitHub
[go: up one dir, main page]

Skip to content

feat: application service types default to any#1566

Merged
daffl merged 1 commit intofeathersjs:dovefrom
vonagam:feat-services-types-any
Mar 20, 2021
Merged

feat: application service types default to any#1566
daffl merged 1 commit intofeathersjs:dovefrom
vonagam:feat-services-types-any

Conversation

@vonagam
Copy link
Member
@vonagam vonagam commented Sep 19, 2019

In #1364 ServiceTypes default changed from any to {} with an intention to make app.service() act more strict when ServiceTypes is provided. Desired outcome and expected type resolution (specified in second comment from that PR) were right, but the solution had a flaw.

When you make ServiceTypes default to {}, Application without parameters (like in HookContext) becomes Application< {} >. And you can't assign Application< {} > to Application< MyServiceTypes >:

const app: Application< MyServiceTypes > = context.app; // error
const app: Application< MyServiceTypes > = context.app as Application< any >; // works

As shown Application< any > does not have such drawback.

To achieve desired outcome right solution is to simply remove second catch-all service() overload, because when ServiceTypes is any first definition is already catch-all and when ServiceTypes is not any then first definition acts as a strict one.

There is a little breaking change (that why it is not a fix, but a feat) since now {} stops acting as wildcard and not a default value.

@vonagam vonagam force-pushed the feat-services-types-any branch from 11f709e to e12e505 Compare September 21, 2019 19:48
@vonagam vonagam force-pushed the feat-services-types-any branch from e12e505 to 5c666c5 Compare December 15, 2019 22:05
@deskoh
Copy link
Contributor
deskoh commented Feb 23, 2020

This will enforce compulsory typings for all service.
Currently. if ServiceTypes is not defined, all service will default to any.

Possible to have best of both worlds?

@vonagam
Copy link
Member Author
vonagam commented Feb 24, 2020

This will not enforce compulsory typings.

Here is the code which you can check in typescript playground:

interface ApplicationOld< ServiceTypes = {} > {
  service< L extends keyof ServiceTypes >( location: L ): ServiceTypes[ L ];
  service( location: string ): keyof ServiceTypes extends never ? any : never;
}

interface ApplicationNew< ServiceTypes = any > {
  service< L extends keyof ServiceTypes >( location: L ): ServiceTypes[ L ];
}

const oldUnspecified = undefined as any as ApplicationOld;
const oldSpecified = undefined as any as ApplicationOld< { foo: 'bar' } >;
const newUnspecified = undefined as any as ApplicationNew;
const newSpecified = undefined as any as ApplicationNew< { foo: 'bar' } >;

const oldUnFoo = oldUnspecified.service('foo');
const oldUnBaz = oldUnspecified.service('baz');
const oldSeFoo = oldSpecified.service('foo');
const oldSeBaz = oldSpecified.service('baz'); // never
const oldConvert: ApplicationOld<{ foo: 'bar' }> = oldUnspecified; // error;

const newUnFoo = newUnspecified.service('foo');
const newUnBaz = newUnspecified.service('baz');
const newSeFoo = newSpecified.service('foo');
const newSeBaz = newSpecified.service('baz'); // type cheching error
const newConvert: ApplicationNew<{ foo: 'bar' }> = oldUnspecified;

@deskoh
Copy link
Contributor
deskoh commented Feb 29, 2020

Ah. I get it now.

@daffl daffl closed this Jul 11, 2020
@vonagam
Copy link
Member Author
vonagam commented Jul 11, 2020

Was this closed accidentally too?

@daffl daffl added this to the v5 (Dove) milestone Jul 11, 2020
@daffl
Copy link
Member
daffl commented Jul 11, 2020

Dang, yes, sorry. This should also stay open to be either merged or revisited for v5.

@daffl daffl reopened this Jul 11, 2020
@vonagam vonagam force-pushed the feat-services-types-any branch from 5c666c5 to 1da5a09 Compare March 20, 2021 05:51
@vonagam vonagam changed the base branch from master to dove March 20, 2021 05:56
@vonagam
Copy link
Member Author
vonagam commented Mar 20, 2021

Rebased and adapted.

@daffl
Copy link
Member
daffl commented Mar 20, 2021

Great, thank you! Will have a look shortly but if it doesn't break any of the latest tests this should work well.

@daffl daffl merged commit d93ba9a into feathersjs:dove Mar 20, 2021
@daffl
Copy link
Member
daffl commented Mar 20, 2021

Perfect! This totally should fix some of the problems I was having before, too. Will go out with the beta release shortly.

@daffl
Copy link
Member
daffl 8000 commented Mar 20, 2021

Hm, strange, looked like the build passed but is failing once it was merged.

@vonagam
Copy link
Member Author
vonagam commented Mar 20, 2021

Any particular problem?

@daffl
Copy link
Member
daffl commented Mar 20, 2021

Type incompatibility: https://github.com/feathersjs/feathers/runs/2156522850?check_suite_focus=true#step:6:235

Getting the errors locally with the latest dove branch, too 🤔

@daffl
Copy link
Member
daffl commented Mar 20, 2021

I have a feeling this might be something else. The compilation error I'm getting locally has something to do with the grant package.

@daffl
Copy link
Member
daffl commented Mar 20, 2021

Other problem fixed for now and I am getting the same error:

Error: test/index.test.ts(27,11): error TS2322: Type 'import("/home/runner/work/feathers/feathers/packages/express/src/declarations").Application<any, any>' is not assignable to type 'import("/home/runner/work/feathers/feathers/packages/feathers/lib/declarations").Application<any, any>'.
  The types returned by 'service(...)' are incompatible between these types.
    Type 'import("/home/runner/work/feathers/feathers/packages/feathers/lib/declarations").FeathersService<import("/home/runner/work/feathers/feathers/packages/express/src/declarations").Application<any, any>, import("/home/runner/work/feathers/feathers/packages/feathers/lib/declarations").Service<any, Partial<any>>>' is not assignable to type 'import("/home/runner/work/feathers/feathers/packages/feathers/lib/declarations").FeathersService<import("/home/runner/work/feathers/feathers/packages/feathers/lib/declarations").Application<any, any>, import("/home/runner/work/feathers/feathers/packages/feathers/lib/declarations").Service<any, Partial<any>>>'.
      Type 'FeathersService<Application<any, any>, Service<any, Partial<any>>>' is not assignable to type 'ServiceAddons<Application<any, any>, Service<any, Partial<any>>>'.
        Types of property 'hooks' are incompatible.
          Type '(options: HookOptions<Application<any, any>, Service<any, Partial<any>>>) => 

Problem seems to be that the Express app type is no longer compatible with the basic Feathers app type (apparently it was before for some reason).

I tried updating express/src/declarations.ts with the following:

interface ExpressUseHandler<T, ServiceTypes> {
  <L extends keyof ServiceTypes & string> (
    path: L,
    ...middlewareOrService: (
      Express|express.RequestHandler|
      (keyof any extends keyof ServiceTypes ? ServiceInterface<any> : ServiceTypes[L])
    )[]
  ): T;
  (...expressHandlers: express.RequestHandler[]): T;
  (handler: Express|express.ErrorRequestHandler): T;
}

export interface Application<ServiceTypes = any, AppSettings = any>
  extends FeathersApplication<ServiceTypes, AppSettings>, Omit<Express, 'listen'|(keyof FeathersApplication)> {
    listen(port: number, hostname: string, backlog: number, callback?: () => void): Promise<http.Server>;
    listen(port: number, hostname: string, callback?: () => void): Promise<http.Server>;
    listen(port: number|string|any, callback?: () => void): Promise<http.Server>;
    listen(callback?: () => void): Promise<http.Server>;
    use: ExpressUseHandler<this, ServiceTypes>;
  }

But no luck so far.

@vonagam vonagam deleted the feat-services-types-any branch October 27, 2021 04:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

0