fastify / help

Need help with Fastify? File an Issue here.
https://www.fastify.io/
65 stars 8 forks source link

How to preserve type information on object assigned through decorator? #143

Closed mattmazzola closed 4 years ago

mattmazzola commented 4 years ago

You have already researched for similiar issues?

Yes, doesn't seem to be any related and the docs don't seem to deal with this either. They assume javascript, but in typescript you cant access properties that don't exist on the type.

See: https://www.fastify.io/docs/latest/Decorators/#usage

I even looked at what I thought was offical plugin of mongo https://github.com/fastify/fastify-mongodb#usage

What are you trying to achieve or the steps to reproduce?

I want to be able to preserve the type of the decorator so it avoids all hard casting in Typescript which is error prone and less scalable as then changes to the decorated object require type updates in all places of use (consumers)

Assume we apply decorator to root fastify instance to make it available to all children plugins. I would like the type to be preserved when accessing that decorator.

Here is contrived condensed example:

type FooBarBaz = {
  foo: {
    bar: string
  }    
}

const fooBarBaz: FooBarBaz = { foo: { bar: "baz" } }
fastify.decorate('myFooBar', fooBarBaz)

fastify.register((instance, options, done) => {
  instance.get('/foo', async (req, res) => {
    // This is the line that has to access the decorator property and cast it to type so they can be accessed below
    const fooBarBazFromDecorator: FooBarBaz = instance['myFooBar']

    return fooBarBazFromDecorator.bar
  })
})

In my real-word example, I'm doing something similar to the mongo plugin. I'm using TypeORM (Another tool which toutes TypeScript as strong point) and when I create a DB connection and use fastify decorator to make this connection available to other plugins / routes.

index.ts

    const connection = await TORM.createConnection()
    server.decorate('connection', connection)

routes/questions.ts

        const connection: TORM.Connection = fastify['connection']
        const questions = await connection.manager.find(Question)

The square brackets and casting feel like I'm doing something wrong.

The problem is that doing this creates composibility on fastify side but loses type information on TypeORM side. I have to cast it back to TypeORM type.

I wonder what your recommendations are for doing this in a cleaner fashion. I assume I could make a plugin factory that adds consolidates casting to the factory, but this is also adding complexity and I want to stick to docs and recommended pratices.

What was the result you received?

I have to cast the value of property made available from decorator back to original Type and I would like to avoid this if possible. I understand you cant change types at runtime, but I think there should be a cleaner / safer way than I'm currently doing above.

What did you expect?

Expected to have some way to supply a generic parameter to the FastifyInstance which will make that the new type for all instances within a route.

I expected there to be some recommendation for how to handle this in the docs since it seems to use Typescript as one of its strong points for using it.

Context

mcollina commented 4 years ago

@Ethan-Arrowood what do you think?

mattmazzola commented 4 years ago

I was thinking about it a bit more and thought I could better explain the expectation part. I'm not sure if my idea is possible in Typescript. Maybe I just have to live with casting, but at least after this I'll know if there was a better option I was missing.

Here's more details about what I was thinking:

I think the fastify.FastifyInstance object could take another generic parameter that specifies the types added to it.

Here is default as is: image

I was thinking it could be something like this: FastifyInstance<Server, IncomingMessage, ServerResponse, Decorations = {}>

Note: the last Decorations = {} type was proposed

Since the type is optional it's a non-breaking change, in some cases. Those who manually specified types would need to update though.

Internally the types from Decorations object are spread onto the FastifyInstance:

I think the decorate function which currently looks like this: image can return an instance with the Decorators property generated based on the function. (This is the part I'm not sure if it's possible.)

So in my example above. server.decorate('connection', connection) would return a type of FastifyInstance<Server, IncomingMessage, ServerResponse, { 'connection': TypeORM.connection }> I think this would require me to re-assign the server instance on every decorate call in order for the type to change: server = server.decorate('connection', connection) this seems like bit of code smell since it's only for types, but what it means is that the server object now has the updated type used in all operations below this.

Then later when I use server.register that instance of server has the correct type, so when it's forwarded to the plugin, it has the connection property available and no casting is needed.

In other words the instance passed to the plugin function from register is the FastifyInstance<Server, IncomingMessage, ServerResponse, { 'connection': TypeORM.connection }> type.

Hope that makes sense.

chill-cod3r commented 4 years ago

so idk if this is the best way, but it works for my use case and is a little more relaxed than the way above, and i find it pretty nice to encapsulate each type augmentation along with the decorator it belongs with. check out the example decorate plugin in my typescript starter - https://github.com/wolfejw86/fastify-typescript-starter/blob/master/src/plugins/support.ts

it should be noted that this will essentially decorate the fastify instance on the global scope so it is not a perfect solution if you want the typescript types to 100% reflect the exact level of encapsulation. I personally love typescript and use it as a helper, and I'm okay with the types essentially "not telling the truth" in all cases. for example, you decorate an encapsulated plugin and then that method shows up on the global scope, and someone else tries to use it "1 level of encapsulation higher" you will get a successful build but a runtime error.

This is just my opinion too, some people will vehemently disagree with this approach bc "if you use typescript, it's not worth it if the types aren't perfect". I'm just not in that camp. I use it for fast refactoring, documentation, more self explanatory code, and well thought out static analysis that catches a lot of but not all errors at build time.

Ethan-Arrowood commented 4 years ago

@wolfejw86 statement is pretty much on point.

What you're trying to achieve @mattmazzola is considered unsafe (in regards to strictly typing). Rather than adding another generic, you should use declaration merging to decorate the fastify instance with whichever custom properties you want. This pattern is documented in the TypeScript/Plugin section.

The better way to do this is through encapsulated type casting.

No true right or wrong way to do things as @wolfejw86 pointed out - its up to you how you want to use the tools provided for you!

chill-cod3r commented 4 years ago

@Ethan-Arrowood would you possibly be able to provide a small example of what you're describing as encapsulated type casting?

Ethan-Arrowood commented 4 years ago

After calling .decorate you create a new variable that is casted to the newly typed instance.

Off the top of my head I'm thinking something like this maybe?

const server = fastify()
server.decorate('foo', 'bar')
const decoratedServer = server as FastifyInstance & { foo: string }
mattmazzola commented 4 years ago

Ok, well I have changed my code to use the "declaration merging" technique from the sample. I consider it an improvement for scalability (types only defined in one place, instead of casted in each consuming plugin)

I was wondering if there is a way to make plugins have dependencies similar to decorator dependencies: https://www.fastify.io/docs/latest/Decorators/#dependencies to help against the runtime errors of declaration merging. In my example, I could define my route plugins depend on the db connection plugin or something.

As for the example above showing "encapsulated type casting". It seems very similar to idea proposed above as type reassignment; however, it still suffers from the larger error of manual type assignment which is possibly wrong or goes stale as decorator changes.

The idea I proposed originally (which I'm not sure is possible) is the decorate function generating the correct type output. Likely using typeof or ReturnType<> to infer what the user put. In this case it would be known that foo is a string because you assigned bar, and don't need to redefine this on the type. This automatic inferring of types where types get out of your way and work correctly is by default is what make typescript feel good to use.

Also, for the declaration merging you could add undefined in to the type since it's possible to access before the decorator runs then make all the dependent plugins type guard first.

mattmazzola commented 4 years ago

As above I have tried the "declaration merging" technique and I believe it would work for most people. However, after further development I am hitting a problem and had to drop the types which nullifies benefits of the declaration merging and makes me think we need another solution to solve this in more natural/robust way that doesn't use declaration merging. (I'll try to explain why below).

If I keep the types the server won't compile/run and am not sure of a way around this. Based on my understanding there is a deadlock situation between different incompatible requirements from types and libraries.

I was using declaration merging like this:

declare module 'fastify' {
    export interface FastifyInstance {
        connection: TORM.Connection
        authenticate: FastifyMiddleware
    }

    export interface FastifyRequest {
        user: Auth0User
    }
}

Then in my route I was adding type information like so:

function (fastify: fastify.FastifyInstance, pluginOptions: unknown, done) {
   ...
   preValidation: [fastify.authenticate],
   ...
   async (req: fastify.FastifyRequest, res) => {
      ...
      await connection.manager.save(userEntity)

Notice: the explicit types on the fastify instance and req object, which allow my connection, authenticate, and user properties to have types from the declaration merge instead of defaulting to any.

Trying to run this results in errors:


> sc2iq-service@0.0.1 start E:\Repos\sc2\iq\service
> ts-node src/index.ts

E:\Repos\sc2\iq\service\node_modules\ts-node\src\index.ts:307
        throw new TSError(formatDiagnostics(diagnosticList, cwd, ts, lineOffset))
              ^
TSError: ⨯ Unable to compile TypeScript
src\routes\users.ts (18,32): Property 'connection' does not exist on type 'FastifyInstance<Server, IncomingMessage, ServerResponse>'. (2339)
src\routes\users.ts (29,37): Property 'authenticate' does not exist on type 'FastifyInstance<Server, 
IncomingMessage, ServerResponse>'. (2339)
src\routes\users.ts (38,33): Property 'user' does not exist on type 'FastifyRequest<IncomingMessage, 
DefaultQuery, DefaultParams, DefaultHeaders, any>'. (2339)
    at getOutput (E:\Repos\sc2\iq\service\node_modules\ts-node\src\index.ts:307:15)
    at Module.m._compile (E:\Repos\sc2\iq\service\node_modules\ts-node\src\index.ts:392:43)
    at Module._extensions..js (internal/modules/cjs/loader.js:785:10)
    at Object.require.extensions.<computed> [as .ts] (E:\Repos\sc2\iq\service\node_modules\ts-node\src\index.ts:395:12)
    at Module.load (internal/modules/cjs/loader.js:641:32)
    at Function.Module._load (internal/modules/cjs/loader.js:556:12)
    at Module.require (internal/modules/cjs/loader.js:681:19)
    at require (internal/modules/cjs/helpers.js:16:16)
npm ERR! code ELIFECYCLE
npm ERR! errno 1

I spent many hours trying to understand the problem. The error is unreliable and only shows at runtime under certain circumstances depending on which types are use which makes very difficult to understand. I had other routes that use these explicit types to have strong types on these properties and the server worked fine. Then I added another route and had one thing different and saw the errors and unraveled this whole thing.

The error is silly because it's obvious the properties are their from the run plugins and decorators. Also, you can view the properties using intellisense from VS code as it finds the definition from the declaration merge, yet when you run it fails, maddening.

Because I'm using TypeORM, it scaffolds the project and seems to suggest using ts-node. However, it urns out ts-node doesn't support declaration merging. https://github.com/TypeStrong/ts-node/issues/715

This is why ts-node was throwing runtime errors. Because it doesn't seem to know about the extensions added by the declaration merge.

There seems to be a solution to use both: https://github.com/TypeStrong/ts-node/issues/715#issuecomment-526757308 However, I could not figure out how to make it work. When I try to create the .d.ts file yet it is suppose to reference types from other external libraries (like adding TypeORM connectdion to fastify instance)

The other crazy thing is you would think Ok if ts-node is the issue lets go around ts-node.

There is another error:

node_modules/@types/readable-stream/index.d.ts:138:18 - error TS2749: 'StringDecoder' refers to a value, but is being used as a type here.

138         decoder: StringDecoder | null;
                     ~~~~~~~~~~~~~

I'm not quite sure of this error but I believe has to do with compilation target or something. Then if you use the special "skipLibCheck" in tsconfig to ignore this. You get another error...


E:\Repos\sc2\iq\service\src\index.ts:1
import "reflect-metadata"
       ^^^^^^^^^^^^^^^^^^

SyntaxError: Unexpected string

Anyways, this is very long explanation of deadlock. TypeORM seems to work best with ts-node which doens't easily support declaration merging, and the recommending to strong type fastify decorators is declaration merging.

I'm sure there is some way to make this work but even if there was it seems like it would require bunch of custom setup which diverges from standard docs.

Hope that made sense, and at very least can help someone else who was going through all similar situation, at best maybe someone knows a solution and maybe this is some motivation to have alternative than declaration merging.

chill-cod3r commented 4 years ago

Interestingly enough I am using Typeorm as well and have no problems. I have never heard the statement TypeORM works best with TS-Node but Tbh I never run my code with TS-node since (at least the last time I checked) it wasn’t recommended to run production code in TSnode and it can produce strange inconsistencies that would lead to painful debugging. Instead I just run off the dist folder using fastify-cli and have it reload when I save. If it would be helpful I can post my typescript version, tsconfig, and my start command.

On Sat, Feb 29, 2020 at 1:27 AM Matt Mazzola notifications@github.com wrote:

As above I have tried the "declaration merging" technique and I believe it would work for most people. However, after further development I am hitting a problem and had to drop the types which nullifies benefits of the declaration merging and makes me think we need another solution to solve this in more natural/robust way that doesn't use declaration merging. (I'll try to explain why below).

If I keep the types the server won't compile/run and am not sure of a way around this. Based on my understanding there is a deadlock situation between different incompatible requirements from types and libraries.

I was using declaration merging like this:

declare module 'fastify' {

export interface FastifyInstance {

    connection: TORM.Connection

    authenticate: FastifyMiddleware

}

export interface FastifyRequest {

    user: Auth0User

}

}

Then in my route I was adding type information like so:

function (fastify: fastify.FastifyInstance, pluginOptions: unknown, done) {

...

preValidation: [fastify.authenticate],

...

async (req: fastify.FastifyRequest, res) => {

  ...

  await connection.manager.save(userEntity)

Notice: the explicit types on the fastify instance and req object, which allow my connection, authenticate, and user properties to have types from the declaration merge instead of defaulting to any.

Trying to run this results in errors:

sc2iq-service@0.0.1 start E:\Repos\sc2\iq\service

ts-node src/index.ts

E:\Repos\sc2\iq\service\node_modules\ts-node\src\index.ts:307

    throw new TSError(formatDiagnostics(diagnosticList, cwd, ts, lineOffset))

          ^

TSError: ⨯ Unable to compile TypeScript

src\routes\users.ts (18,32): Property 'connection' does not exist on type 'FastifyInstance<Server, IncomingMessage, ServerResponse>'. (2339)

src\routes\users.ts (29,37): Property 'authenticate' does not exist on type 'FastifyInstance<Server,

IncomingMessage, ServerResponse>'. (2339)

src\routes\users.ts (38,33): Property 'user' does not exist on type 'FastifyRequest<IncomingMessage,

DefaultQuery, DefaultParams, DefaultHeaders, any>'. (2339)

at getOutput (E:\Repos\sc2\iq\service\node_modules\ts-node\src\index.ts:307:15)

at Module.m._compile (E:\Repos\sc2\iq\service\node_modules\ts-node\src\index.ts:392:43)

at Module._extensions..js (internal/modules/cjs/loader.js:785:10)

at Object.require.extensions.<computed> [as .ts] (E:\Repos\sc2\iq\service\node_modules\ts-node\src\index.ts:395:12)

at Module.load (internal/modules/cjs/loader.js:641:32)

at Function.Module._load (internal/modules/cjs/loader.js:556:12)

at Module.require (internal/modules/cjs/loader.js:681:19)

at require (internal/modules/cjs/helpers.js:16:16)

npm ERR! code ELIFECYCLE

npm ERR! errno 1

I spent many hours trying to understand the problem. The error is unreliable and only shows at runtime under certain circumstances depending on which types are use which makes very difficult to understand. I had other routes that use these explicit types to have strong types on these properties and the server worked fine. Then I added another route and had one thing different and saw the errors and unraveled this whole thing.

The error is silly because it's obvious the properties are their from the run plugins and decorators. Also, you can view the properties using intellisense from VS code as it finds the definition from the declaration merge, yet when you run it fails, maddening.

Because I'm using TypeORM, it scaffolds the project and seems to suggest using ts-node. However, it urns out ts-node doesn't support declaration merging. TypeStrong/ts-node#715 https://github.com/TypeStrong/ts-node/issues/715

This is why ts-node was throwing runtime errors. Because it doesn't seem to know about the extensions added by the declaration merge.

There seems to be a solution to use both: TypeStrong/ts-node#715 (comment) https://github.com/TypeStrong/ts-node/issues/715#issuecomment-526757308 However, I could not figure out how to make it work. When I try to create the .d.ts file yet it is suppose to reference types from other external libraries (like adding TypeORM connectdion to fastify instance)

The other crazy thing is you would think Ok if ts-node is the issue lets go around ts-node.

There is another error:

node_modules/@types/readable-stream/index.d.ts:138:18 - error TS2749: 'StringDecoder' refers to a value, but is being used as a type here.

138 decoder: StringDecoder | null;

                 ~~~~~~~~~~~~~

I'm not quite sure of this error but I believe has to do with compilation target or something. Then if you use the special "skipLibCheck" in tsconfig to ignore this. You get another error...

E:\Repos\sc2\iq\service\src\index.ts:1

import "reflect-metadata"

   ^^^^^^^^^^^^^^^^^^

SyntaxError: Unexpected string

Anyways, this is very long explanation of deadlock. TypeORM seems to work best with ts-node which doens't easily support declaration merging, and the recommending to strong type fastify decorators is declaration merging.

I'm sure there is some way to make this work but even if there was it seems like it would require bunch of custom setup which diverges from standard docs.

Hope that made sense, and at very least can help someone else who was going through all similar situation, at best maybe someone knows a solution and maybe this is some motivation to have alternative than declaration merging.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/fastify/help/issues/143?email_source=notifications&email_token=AFI3Y3KK3VRNQM5MXOXETIDRFH567A5CNFSM4KV5L7U2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOENLQQIY#issuecomment-592906275, or unsubscribe https://github.com/notifications/unsubscribe-auth/AFI3Y3IGAXQTCFRC4VZHOZDRFH567ANCNFSM4KV5L7UQ .

mattmazzola commented 4 years ago

From your reply, I understand you're running TypeORM without ts-node.

I was following their Quick Start guide here: https://typeorm.io/#/quick-start npx typeorm init --name MyProject --database mysql

This generates a project with ts-node and has all the config such as entities, migrations, and things, in the src .ts directories.

If I simply change it to use node, it is still configured to load these directories at runtime and will fail when trying to evaluate a .ts file. I will try to update my repo to make it public so I can share my config.

It sounds like my next best step is get it working without ts-node so that the declaration merging works. (Or perhaps use Deno?)

I would be interested to see your repos config if it's public. I'll try to work on this and get back.

chill-cod3r commented 4 years ago

Yes, I forgot that I also had to work through their "default" setup that just uses ts-node but fails completely if you try to run it as a "built" javascript app. For starters here's how I manage my dbconnection -

import path from 'path';
import fp from 'fastify-plugin';

import { createConnection, Connection, getRepository } from 'typeorm';

const dbConnection = fp(
  async fastify => {
    const connection = await createConnection({
      type: 'postgres',
      url: fastify.appConfig.postgresURI,
      ssl: fastify.appConfig.environment !== 'development',
      synchronize: false,
      logging: fastify.appConfig.environment === 'development',
      migrationsRun: true,
      entities: [path.join(__dirname, '../entity/**/*')],
      migrations: [path.join(__dirname, '../migration/**/*')],
    });

    fastify
      .decorate('orm', {
        getRepository,
        connection,
        close: () => connection.close(),
      })
      .addHook('onClose', async (instance, done) => {
        await instance.orm.close();
        done();
      });
  },
  { name: 'db-connection' },
);

export default dbConnection;
module.exports = dbConnection;

declare module 'fastify' {
  export interface FastifyInstance {
    orm: {
      connection: Connection;
      getRepository: typeof getRepository;
      close: () => Promise<void>;
    };
  }
}

notice I intentionally stay away from the JSON file in the root of the repo config as that doesn't work well with private variables in my opinion.

here's my tsconfig:

{
  "compilerOptions": {
    /* Basic Options */
    "target": "es2019" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */,
    "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
    "lib": [
      "es6"
    ] /* Specify library files to be included in the compilation. */,
    "allowJs": true /* Allow javascript files to be compiled. */,
    // "checkJs": true,                       /* Report errors in .js files. */
    // "jsx": "preserve",                     /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
    // "declaration": true,                   /* Generates corresponding '.d.ts' file. */
    "sourceMap": true /* Generates corresponding '.map' file. */,
    // "outFile": "./",                       /* Concatenate and emit output to single file. */
    "outDir": "dist" /* Redirect output structure to the directory. */,
    "rootDir": "src",                       /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
    // "removeComments": true,                /* Do not emit comments to output. */
    // "noEmit": true,                        /* Do not emit outputs. */
    // "importHelpers": true,                 /* Import emit helpers from 'tslib'. */
    // "downlevelIteration": true,            /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
    // "isolatedModules": true,               /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
    /* Strict Type-Checking Options */
    "strict": true /* Enable all strict type-checking options. */,
    "noImplicitAny": true,                 /* Raise error on expressions and declarations with an implied 'any' type. */
    "strictNullChecks": true,              /* Enable strict null checks. */
    // "strictFunctionTypes": true,           /* Enable strict checking of function types. */
    "strictPropertyInitialization": false,  /* Enable strict checking of property initialization in classes. */
    // "noImplicitThis": true,                /* Raise error on 'this' expressions with an implied 'any' type. */
    "alwaysStrict": true,                  /* Parse in strict mode and emit "use strict" for each source file. */
    /* Additional Checks */
    "noUnusedLocals": true /* Report errors on unused locals. */,
    "noUnusedParameters": false,            /* Report errors on unused parameters. */
    // "noImplicitReturns": true,             /* Report error when not all code paths in function return a value. */
    // "noFallthroughCasesInSwitch": true,    /* Report errors for fallthrough cases in switch statement. */
    /* Module Resolution Options */
    "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,
    // "baseUrl": "." /* Base directory to resolve non-absolute module names. */,
    // "paths": {},                           /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
    // "rootDirs": [],                        /* List of root folders whose combined content represents the structure of the project at runtime. */
    "typeRoots": [
      "src/types/*.d.ts",
      "node_modules/@types"
    ] /* List of folders to include type definitions from. */,
    // "types": [],                           /* Type declaration files to be included in compilation. */
    // "allowSyntheticDefaultImports": true,  /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
    "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
    // "preserveSymlinks": true,              /* Do not resolve the real path of symlinks. */
    /* Source Map Options */
    // "sourceRoot": "./",                    /* Specify the location where debugger should locate TypeScript files instead of source locations. */
    // "mapRoot": "./",                       /* Specify the location where debugger should locate map files instead of generated locations. */
    // "inlineSourceMap": true,               /* Emit a single file with source maps instead of having a separate file. */
    // "inlineSources": true,                 /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
    /* Experimental Options */
    "experimentalDecorators": true /* Enables experimental support for ES7 decorators. */,
    "emitDecoratorMetadata": true /* Enables experimental support for emitting type metadata for decorators. */
  },
  "include": ["src/**/*"]
}

I am also on Typescript version 3.7.4.

One last thing I forgot to mention above, I have also had even more trouble augmenting a decorated request object than a decorated fastify instance. I actually quit trying on the request object and instead just ensure that my route / payload validations are 100% accurate and then force the type. for instance const bodyData: MyBodyDataInterface = request.body; In the case of using the middleware pattern (such as looking up a user from the database and attaching the instance to the request object like in the express days) I REALLY haven't found a good way to do it. Currently I do request.req.user = userObject which requires a forced type assertion to attach and then another one to "pull it back off". I'm still looking for answers to these things and better ways to do them, but at the end of the day there's other problems to solve too :) I put those out there hoping to hear from anyone who has a better way of doing it 🤞 I hope some of this helps!

mattmazzola commented 4 years ago

Thanks helping and posting your config!

I'm still polishing things but I at least got it to run with proper types without ts-node using a similar configuration based off the one you used.

I'm not sure how you were able to enable "strict": true (I get bunch of errors on the Entities about lack of initializers and other untyped any objects), but without I still have decent types of fastify instance and request which is what I wanted so I don't need it. I now have the typed properties from decorators (connection, authenticate) and user which is sufficient for most cases and I should be able to extend as needed.

I was wondering if fastify.appConfig is some custom thing for your app, or a standard plugin to work with config?

stale[bot] commented 4 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.