/** * Primitive type of JSON. * * `Primitive` is a TMP (Type Meta Programming) type which converts * its argument as a primitive type within framework JSON. * * If the target argument is a built-in class which returns its origin primitive type * through the `valueOf()` method like the `String` or `Number`, its return type would * be the `string` or `number`. Otherwise, the built-in class does not have the * `valueOf()` method, the return type would be an empty object (`{}`). * * Otherwise, the target argument is a type of custom class, all of its custom method * would be erased and its prototype would be changed to the primitive `object`. * Therefore, return type of the TMP type finally be the primitive object. * * In addition, if the target argument is a type of custom class and it has a special * method `toJSON()`, return type of this `Primitive` would be not `Primitive` * but `Primitive>`. * * Before | After * ------------------------|---------------------------------------- * `Boolean` | `boolean` * `Number` | `number` * `String` | `string` * `Class` | `object` * `Class` with `toJSON()` | `Primitive>` * Native Class | never * Others | No change * * @template T Target argument type. * @author Jeongho Nam - https://github.com/samchon * @author Kyungsu Kang - https://github.com/kakasoo * @author Michael - https://github.com/8471919 */ export type Primitive = Equal> extends true ? T : PrimitiveMain; type Equal = X extends Y ? (Y extends X ? true : false) : false; type PrimitiveMain = Instance extends [never] ? never // (special trick for jsonable | null) type : ValueOf extends bigint ? never : ValueOf extends boolean | number | string ? ValueOf : Instance extends Function ? never : ValueOf extends object ? Instance extends object ? Instance extends NativeClass ? never : Instance extends IJsonable ? ValueOf extends object ? Raw extends object ? PrimitiveObject // object would be primitified : never // cannot be : ValueOf // atomic value : PrimitiveObject // object would be primitified : never // cannot be : ValueOf; type PrimitiveObject = Instance extends Array ? IsTuple extends true ? PrimitiveTuple : PrimitiveMain[] : { [P in keyof Instance]: PrimitiveMain; }; type PrimitiveTuple = T extends [] ? [] : T extends [infer F] ? [PrimitiveMain] : T extends [infer F, ...infer Rest extends readonly any[]] ? [PrimitiveMain, ...PrimitiveTuple] : T extends [(infer F)?] ? [PrimitiveMain?] : T extends [(infer F)?, ...infer Rest extends readonly any[]] ? [PrimitiveMain?, ...PrimitiveTuple] : []; type ValueOf = IsValueOf extends true ? boolean : IsValueOf extends true ? number : IsValueOf extends true ? string : Instance; type NativeClass = | Set | Map | WeakSet | WeakMap | Uint8Array | Uint8ClampedArray | Uint16Array | Uint32Array | BigUint64Array | Int8Array | Int16Array | Int32Array | BigInt64Array | Float32Array | Float64Array | ArrayBuffer | SharedArrayBuffer | DataView; type IsTuple = [T] extends [ never, ] ? false : T extends readonly any[] ? number extends T["length"] ? false : true : false; type IsValueOf> = Instance extends Object ? Object extends IValueOf ? Instance extends U ? false : true // not Primitive, but Object : false // cannot be : false; interface IValueOf { valueOf(): T; } interface IJsonable { toJSON(): T; }