Skip to content

Commit

Permalink
feat(build): add more TypeScript "strict" checks
Browse files Browse the repository at this point in the history
Enable all "strict" checks with the exception of
`strictPropertyInitialization` which would require significant changes.

The following additional checks are added:

- noImplicitThis
- alwaysStrict
- strictFunctionTypes

In the future, any checks added to TypeScript "strict" mode will be
automatically enabled for LoopBack projects too.
  • Loading branch information
bajtos committed Apr 8, 2019
1 parent 74a0d60 commit 82cdcd6
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 19 deletions.
9 changes: 7 additions & 2 deletions benchmark/src/benchmark.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import * as byline from 'byline';
import {ChildProcess, spawn} from 'child_process';
import pEvent from 'p-event';
import pEvent, {Emitter} from 'p-event';
import {Autocannon, EndpointStats} from './autocannon';
import {Client} from './client';
import {scenarios} from './scenarios';
Expand Down Expand Up @@ -111,5 +111,10 @@ function startWorker() {

async function closeWorker(worker: ChildProcess) {
worker.kill();
await pEvent(worker, 'close');
await pEvent(
// workaround for a bug in pEvent types which makes them
// incompatible with "strictFunctionTypes"
worker as Emitter<[unknown]>,
'close',
);
}
7 changes: 4 additions & 3 deletions packages/build/config/tsconfig.common.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
"compilerOptions": {
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"noImplicitAny": true,
"strictNullChecks": true,
"resolveJsonModule": true,
"strictBindCallApply": true,
"skipLibCheck": true,
"strict": true,

// FIXME(bajtos) LB4 is not compatible with this setting yet
"strictPropertyInitialization": false,

"lib": ["es2018", "esnext.asynciterable"],
"module": "commonjs",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -458,8 +458,8 @@ describe('Context bindings - Injecting dependencies of classes', () => {
'location',
{},
// Set up a custom resolve() to access information from the session
(c: Context, injection: Injection, session: ResolutionSession) => {
resolutionPath = session.getResolutionPath();
(c: Context, injection: Injection, session?: ResolutionSession) => {
resolutionPath = session ? session.getResolutionPath() : undefined;
return 'San Jose';
},
)
Expand Down
12 changes: 9 additions & 3 deletions packages/context/src/__tests__/unit/resolver.unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,9 @@ describe('constructor injection', () => {
'p',
{},
// Set up a custom resolve() to access information from the session
(c: Context, injection: Injection, session: ResolutionSession) => {
(c: Context, injection: Injection, session?: ResolutionSession) => {
if (!session)
throw new Error('Resolver was called with no ResolutionSession');
bindingPath = session.getBindingPath();
resolutionPath = session.getResolutionPath();
},
Expand Down Expand Up @@ -251,7 +253,9 @@ describe('constructor injection', () => {
'p',
{},
// Set up a custom resolve() to access information from the session
(c: Context, injection: Injection, session: ResolutionSession) => {
(c: Context, injection: Injection, session?: ResolutionSession) => {
if (!session)
throw new Error('Resolver was called with no ResolutionSession');
bindingPath = session.getBindingPath();
resolutionPath = session.getResolutionPath();
decorators = session.injectionStack.map(i => i.metadata!.decorator);
Expand Down Expand Up @@ -290,7 +294,9 @@ describe('constructor injection', () => {
'p',
{},
// Set up a custom resolve() to access information from the session
(c: Context, injection: Injection, session: ResolutionSession) => {
(c: Context, injection: Injection, session?: ResolutionSession) => {
if (!session)
throw new Error('Resolver was called with no ResolutionSession');
injectionPath = session.getInjectionPath();
},
)
Expand Down
20 changes: 13 additions & 7 deletions packages/context/src/context-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,16 @@ export class ContextView<T = unknown> extends EventEmitter
protected _cachedValues: T[] | undefined;
private _subscription: Subscription | undefined;

constructor(
protected readonly context: Context,
public readonly filter: BindingFilter<T>,
) {
// Workaround to pass TypeScript's "strictFunctionTypes" check:
// Type 'BindingFilter<T>' is not assignable to type 'BindingFilter<unknown>'.
// Type 'unknown' is not assignable to type 'T'.
readonly filter: BindingFilter<unknown>;

constructor(protected readonly context: Context, filter: BindingFilter<T>) {
super();

// Workaround to pass TypeScript's "strictFunctionTypes" check
this.filter = filter as BindingFilter<unknown>;
}

/**
Expand Down Expand Up @@ -85,10 +90,11 @@ export class ContextView<T = unknown> extends EventEmitter
/**
* Find matching bindings and refresh the cache
*/
protected findBindings() {
protected findBindings(): Readonly<Binding<T>>[] {
debug('Finding matching bindings');
this._cachedBindings = this.context.find(this.filter);
return this._cachedBindings;
const found = this.context.find(this.filter);
this._cachedBindings = found;
return found;
}

/**
Expand Down
10 changes: 8 additions & 2 deletions packages/repository/src/__tests__/unit/type-resolver.unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@
// License text available at https://opensource.org/licenses/MIT

import {expect} from '@loopback/testlab';
import {isBuiltinType, isTypeResolver, resolveType} from '../../type-resolver';
import {
isBuiltinType,
isTypeResolver,
resolveType,
TypeResolver,
} from '../../type-resolver';

class SomeModel {
constructor(public name: string) {}
Expand Down Expand Up @@ -60,7 +65,8 @@ describe('isTypeResolver', () => {

describe('resolveType', () => {
it('resolves the arg when the value is a resolver', () => {
const ctor = resolveType(() => SomeModel);
const resolver: TypeResolver<SomeModel> = () => SomeModel;
const ctor = resolveType(resolver);
expect(ctor).to.eql(SomeModel);

const inst = new ctor('a-name');
Expand Down

0 comments on commit 82cdcd6

Please sign in to comment.