Skip to content

Commit

Permalink
feat: new Terminal type (Papooch#26)
Browse files Browse the repository at this point in the history
* feat: new Terminal type

* test: fix types test
  • Loading branch information
Papooch authored Mar 29, 2022
1 parent 09c68d9 commit 97ed182
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 2 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,20 @@ declare module 'nestjs-cls' {
}
```

It can happen, that the object you want to store in the context is too complex, or contains cyclic references. In that case, typescript might complain that _type instantiation is too deep, possibly infinite_. That is due to the fact that it tries to generate all possible paths inside the store. If that's the case, you can use the `Terminal` type to stop generating the paths for a certain subtree:

```ts
interface ClsStore {
tenantId: string;
user: Terminal<{
id: number;
authorized: boolean;
}>;
}
```

This will only generate the paths `tenantId | user` and won't allow directly accessing nested keys (like `cls.get('user.id')`, but you'll still get fully typing for things like `const { id } = cls.get('user')`). See issue #22 for more details.

# API

## Service interface
Expand Down
9 changes: 9 additions & 0 deletions src/lib/cls.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Test, TestingModule } from '@nestjs/testing';
import { Terminal } from '../types/recursive-key-of.type';
import { ClsServiceManager } from './cls-service-manager';
import { CLS_DEFAULT_NAMESPACE, CLS_ID } from './cls.constants';
import { ClsStore } from './cls.interfaces';
Expand Down Expand Up @@ -137,6 +138,10 @@ describe('ClsService', () => {
f: Array<string>;
};
g: Map<string, number>;
h: Terminal<{
i: string;
j: number;
}>;
};
}

Expand All @@ -153,6 +158,7 @@ describe('ClsService', () => {
typedService.set('b.d.e', false);
typedService.set('b.d.f', ['x']);
typedService.set('b.g', new Map());
typedService.set('b.h', { i: 'i', j: 1 });

const { a, b } = typedService.get();
a;
Expand All @@ -164,6 +170,9 @@ describe('ClsService', () => {
typedService.get('b.d.e');
typedService.get('b.d.f')[0];
typedService.get('b.g').get('x');
const { i, j } = typedService.get('b.h');
i;
j;
});
});
});
Expand Down
11 changes: 9 additions & 2 deletions src/types/recursive-key-of.type.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
type Terminal =
type TerminalType =
| string
| number
| bigint
Expand All @@ -10,8 +10,15 @@ type Terminal =
| Set<any>
| Date
| RegExp
| BrandedTerminal
| ((...args: any) => any);

const TERMINAL_BRAND = Symbol();
class BrandedTerminal {
private [TERMINAL_BRAND]?: void;
}
export type Terminal<T> = T & BrandedTerminal;

/**
* Deep nested keys of an interface with dot syntax
*
Expand All @@ -21,7 +28,7 @@ type Terminal =
export type RecursiveKeyOf<
T,
Prefix extends string = never,
> = T extends Terminal
> = T extends TerminalType
? never
: {
[K in keyof T & string]: [Prefix] extends [never]
Expand Down

0 comments on commit 97ed182

Please sign in to comment.