-
Notifications
You must be signed in to change notification settings - Fork 0
/
Primitive.ts
113 lines (102 loc) · 3.2 KB
/
Primitive.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/**
* @packageDocumentation
* @module api
*/
//================================================================
/**
* 객체의 원시 타입.
*
* `Primitive` 는 대상 인스턴스의 모든 메서드를 제거하여, 그 타입을 pritimive object 의 형태로
* 바꾸어주는 TMP (Type Meta Programming) 타입이다.
*
* @template Instance 대상 인스턴스
* @author Samchon
*/
export type Primitive<Instance> = value_of<Instance> extends object
? Instance extends object
? Instance extends IJsonable<infer Raw>
? value_of<Raw> extends object
? Raw extends object
? PrimitiveObject<Raw> // object would be primitified
: never // cannot be
: value_of<Raw> // atomic value
: PrimitiveObject<Instance> // object would be primitified
: never // cannot be
: value_of<Instance>;
export namespace Primitive
{
/**
* Primitive object 하드 카피.
*
* `Primitive.clone()` 은 파라미터 인스턴스를 원시 오브젝트 형태로 hard copy 하는 함수이다.
*
* @param instance 복사 대상 인스턴스
* @return 복사된 객체
*/
export function clone<Instance>(instance: Instance): Primitive<Instance>
{
return JSON.parse(JSON.stringify(instance));
}
/**
* @todo
*/
export function equal_to<Instance>(x: Instance, y: Instance): boolean
{
return JSON.stringify(x) === JSON.stringify(y) || recursive_equal_to(x, y);
}
}
type PrimitiveObject<Instance extends object> = Instance extends Array<infer T>
? Primitive<T>[]
:
{
[P in keyof Instance]: Instance[P] extends Function
? never
: Primitive<Instance[P]>
};
type value_of<Instance> =
is_value_of<Instance, Boolean> extends true ? boolean
: is_value_of<Instance, Number> extends true ? number
: is_value_of<Instance, String> extends true ? string
: Instance;
type is_value_of<Instance, Object extends IValueOf<any>> =
Instance extends Object
? Object extends IValueOf<infer Primitive>
? Instance extends Primitive
? false
: true // not Primitive, but Object
: false // cannot be
: false;
interface IValueOf<T>
{
valueOf(): T;
}
interface IJsonable<T>
{
toJSON(): T;
}
function object_equal_to<T extends object>(x: T, y: T): boolean
{
for (const key in x)
if (recursive_equal_to(x[key], y[key]) === false)
return false;
return true;
}
function array_equal_to<T>(x: T[], y: T[]): boolean
{
if (x.length !== y.length)
return false;
return x.every((value, index) => recursive_equal_to(value, y[index]));
}
function recursive_equal_to<T>(x: T, y: T): boolean
{
const type = typeof x;
if (type !== typeof y)
return false;
else if (type === "object")
if (x instanceof Array)
return array_equal_to(x, y as typeof x);
else
return object_equal_to(<any>x as object, <any>y as object);
else
return x === y;
}