Skip to content

Commit

Permalink
fix(type): do not interfere with type checking when intersecting mult…
Browse files Browse the repository at this point in the history
…iple type annotations.

this also adds a new helper type `TypeAnnotation<T, O>` which can be used to create custom type annotations:

```typescript
type PrimaryKey = TypeAnnotation<'primaryKey'>;

type Entity<T extends EntityOptions> = TypeAnnotation<'entity', T>
```
  • Loading branch information
marcj committed Oct 10, 2023
1 parent b3f6ea6 commit af85f1f
Show file tree
Hide file tree
Showing 14 changed files with 206 additions and 102 deletions.
4 changes: 2 additions & 2 deletions packages/app/src/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
*/

import { ClassType } from '@deepkit/core';
import { ClassDecoratorResult, createClassDecoratorContext, createPropertyDecoratorContext, FreeFluidDecorator, PropertyApiTypeInterface } from '@deepkit/type';
import { ClassDecoratorResult, createClassDecoratorContext, createPropertyDecoratorContext, FreeFluidDecorator, PropertyApiTypeInterface, TypeAnnotation } from '@deepkit/type';

/**
* Flag is a command line argument that is prefixed with `--` and can have a value.
*/
export type Flag<Options extends {char?: string, hidden?: boolean} = {}> = { __meta?: ['cli:flag', Options] };
export type Flag<Options extends {char?: string, hidden?: boolean} = {}> = TypeAnnotation<'cli:flag', Options>;

class ArgDefinitions {
name: string = '';
Expand Down
2 changes: 1 addition & 1 deletion packages/desktop-ui/src/components/app/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import onChange from 'on-change';
* }
* ```
*/
export type PartOfUrl = { __meta?: ['partOfUrl'] };
export type PartOfUrl = { __meta?: never & ['partOfUrl'] };

export type FilterActions<T> = { [name in keyof T]: T[name] extends (a: infer A extends [...a: any[]], ...args: any[]) => infer R ? (...args: A) => R : never };

Expand Down
16 changes: 8 additions & 8 deletions packages/http/src/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { IncomingMessage, OutgoingHttpHeader, OutgoingHttpHeaders, ServerRespons
import { UploadedFile } from './router.js';
import * as querystring from 'querystring';
import { Writable } from 'stream';
import { metaAnnotation, ReflectionKind, Type, ValidationErrorItem } from '@deepkit/type';
import { metaAnnotation, ReflectionKind, Type, ValidationErrorItem, TypeAnnotation } from '@deepkit/type';
import { asyncOperation, isArray } from '@deepkit/core';

export class HttpResponse extends ServerResponse {
Expand Down Expand Up @@ -116,12 +116,12 @@ export class ValidatedBody<T> {
}
}

export type HttpBody<T> = T & { __meta?: ['httpBody'] };
export type HttpBodyValidation<T> = ValidatedBody<T> & { __meta?: ['httpBodyValidation'] };
export type HttpPath<T, Options extends { name?: string } = {}> = T & { __meta?: ['httpPath', Options] };
export type HttpHeader<T, Options extends { name?: string } = {}> = T & { __meta?: ['httpHeader', Options] };
export type HttpQuery<T, Options extends { name?: string } = {}> = T & { __meta?: ['httpQuery', Options] };
export type HttpQueries<T, Options extends { name?: string } = {}> = T & { __meta?: ['httpQueries', Options] };
export type HttpBody<T> = T & TypeAnnotation<'httpBody'>;
export type HttpBodyValidation<T> = ValidatedBody<T> & TypeAnnotation<'httpBodyValidation'>;
export type HttpPath<T, Options extends { name?: string } = {}> = T & TypeAnnotation<'httpPath', Options>;
export type HttpHeader<T, Options extends { name?: string } = {}> = T & TypeAnnotation<'httpHeader'>;
export type HttpQuery<T, Options extends { name?: string } = {}> = T & TypeAnnotation<'httpQuery', Options>;
export type HttpQueries<T, Options extends { name?: string } = {}> = T & TypeAnnotation<'httpQueries', Options>;

/**
* For all parameters used in the URL path, a regular expression of /[^/]+/ is used. To change that, use getRegExp.
Expand All @@ -137,7 +137,7 @@ export type HttpQueries<T, Options extends { name?: string } = {}> = T & { __met
* }
* ```
*/
export type HttpRegExp<T, Pattern extends string | RegExp> = T & { __meta?: ['httpRegExp', Pattern] };
export type HttpRegExp<T, Pattern extends string | RegExp> = T & { __meta?: never & ['httpRegExp', Pattern] };

export function getRegExp(type: Type): string | RegExp | undefined {
const options = metaAnnotation.getForName(type, 'httpRegExp');
Expand Down
2 changes: 1 addition & 1 deletion packages/http/tests/router.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1021,7 +1021,7 @@ test('unpopulated entity without type information', async () => {
});

test('extend with custom type', async () => {
type StringifyTransport = { __meta?: ['stringifyTransport'] };
type StringifyTransport = { __meta?: never & ['stringifyTransport'] };

function isStringifyTransportType(type: Type): boolean {
return !!metaAnnotation.getForName(type, 'stringifyTransport');
Expand Down
20 changes: 18 additions & 2 deletions packages/orm/tests/query.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
import { BackReference, deserialize, PrimaryKey, Reference } from '@deepkit/type';
import { BackReference, deserialize, Index, PrimaryKey, Reference, UUID, uuid } from '@deepkit/type';
import { expect, test } from '@jest/globals';
import { assert, IsExact } from 'conditional-type-checks';
import { Database } from '../src/database.js';
import { MemoryDatabaseAdapter, MemoryQuery } from '../src/memory-db.js';
import { AnyQuery, BaseQuery, Query } from '../src/query.js';
import { AnyQuery, Query } from '../src/query.js';
import { OrmEntity } from '../src/type.js';

test('types do not interfere with type check', () => {
class Books {
bookId: UUID & Index = uuid();
}

const database = new Database(new MemoryDatabaseAdapter());

function get(bookId: UUID) {
return database
.query(Books)
// this should just compile and not error
.filter({ bookId })
.findOneOrUndefined();
}
});

test('query select', async () => {
class s {
id!: number & PrimaryKey;
Expand Down
Loading

0 comments on commit af85f1f

Please sign in to comment.