Skip to content

Commit

Permalink
fix(type): resolve global classes as shallow TypeClass
Browse files Browse the repository at this point in the history
For example `resolveReceiveType(Date)` or `resolveReceiveType(Error)` should resolve a shallow TypeClass (a TypeClass with empty types array).
  • Loading branch information
marcj committed May 4, 2024
1 parent 2e82eb6 commit d976024
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 9 deletions.
15 changes: 15 additions & 0 deletions packages/core/src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,21 @@ export function isClass(obj: any): obj is AbstractClassType {
return false;
}

declare var global: any;
declare var window: any;

export function isGlobalClass(obj: any): obj is AbstractClassType {
if ('function' !== typeof obj) return false;

if ('undefined' !== typeof window) {
return (window as any)[getClassName(obj)] === obj;
}
if ('undefined' !== typeof global) {
return (global as any)[getClassName(obj)] === obj;
}
return false;
}

/**
* Returns true for real objects: object literals ({}) or class instances (new MyClass).
*
Expand Down
16 changes: 16 additions & 0 deletions packages/core/tests/core.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
isClassInstance,
isConstructable,
isFunction,
isGlobalClass,
isIterable,
isNumeric,
isObject,
Expand Down Expand Up @@ -604,3 +605,18 @@ test('iterableSize', () => {
expect(iterableSize(new Set([1, 2, 3]) as any)).toBe(3);
});

test('isGlobalClass', () => {
expect(isGlobalClass(undefined)).toBe(false);
expect(isGlobalClass({})).toBe(false);

expect(isGlobalClass(Date)).toBe(true);
expect(isGlobalClass(Array)).toBe(true);
expect(isGlobalClass(TextDecoder)).toBe(true);

class MyError extends Error {
}
expect(isGlobalClass(Error)).toBe(true);
expect(isGlobalClass(MyError)).toBe(false);

expect(isGlobalClass(Uint8Array)).toBe(true);
});
5 changes: 3 additions & 2 deletions packages/type/src/reflection/reflection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import {
getClassName,
isArray,
isClass,
isGlobalClass,
isPrototypeOfBase,
stringifyValueWithType,
} from '@deepkit/core';
Expand Down Expand Up @@ -104,10 +105,10 @@ export function resolveReceiveType(type?: Packed | Type | ClassType | AbstractCl
if (type instanceof ReflectionClass) return type.type;
if (isArray(type) && type.__type) return type.__type;
if (isType(type)) return type as Type;
if (isClass(type)) {
if (isClass(type) || isGlobalClass(type)) {
if (!('__type' in type)) {
if ((type as any).__cached_type) return (type as any).__cached_type;
// disabled reflection for this class, so we return empty TypeClass
// disabled reflection for this class, so we return shallow TypeClass
return (type as any).__cached_type = { kind: ReflectionKind.class, classType: type as any, types: [] } as any;
}
return resolveRuntimeType(type) as Type;
Expand Down
9 changes: 2 additions & 7 deletions packages/type/src/reflection/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
indent,
isArray,
isClass,
isGlobalClass,
} from '@deepkit/core';
import { TypeNumberBrand } from '@deepkit/type-spec';
import { getProperty, ReceiveType, reflect, ReflectionClass, resolveReceiveType, toSignature } from './reflection.js';
Expand Down Expand Up @@ -2285,13 +2286,7 @@ export const binaryTypes: ClassType[] = [
*/
export function isGlobalTypeClass(type: Type): type is TypeClass {
if (type.kind !== ReflectionKind.class) return false;
if ('undefined' !== typeof window) {
return (window as any)[getClassName(type.classType)] === type.classType;
}
if ('undefined' !== typeof global) {
return (global as any)[getClassName(type.classType)] === type.classType;
}
return false;
return isGlobalClass(type.classType);
}

/**
Expand Down

0 comments on commit d976024

Please sign in to comment.