Repository: TypeScript
Issue: Add a new helper type `Primitive` for JSON
Labels: Suggestion,Awaiting More Feedback

## Search Terms
  - Primitive
  - JSON

## Suggestion
When you encode an object to a JSON-string and decode the JSON-string to an object again, the object would be primitive. All of the methods defined in the object would be removed and its `prototype` would also be the primitive `Object`. 

> If the target object has a `toJSON()` method, it would be converted to a pritimive of returned value from the `toJSON()` method.

To express those conversions, I suggest a new helper type `Primitive`. I believe that providing the helper type `Primitive` is much better choice rather than hard-coding; enforcing programmers to implement duplicated (primitive) type definition, by themselves, considering the JSON encoding & decoding.

Below is the implementation code:

```typescript
/**
 * Primitify a type.
 * 
 * If target type is an object, all methods defined in the object would be 
 * removed. Also, if the target type has a `toJSON()` method, its return type 
 * would be chosen.
 * 
 * @typeParam T A type to be primitive
 */
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>;

/**
 * @hidden
 */
type PrimitiveObject<Instance extends object> =
{
    [P in keyof Instance]: Instance[P] extends Function
        ? never
        : Primitive<Instance[P]>
};

/**
 * @hidden
 */
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;

/**
 * @hidden
 */
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;

/**
 * @hidden
 */
interface IValueOf<T>
{
    valueOf(): T;
}
```


## Use Cases
```typescript
interface IMember
{
    id: Number;
    name: string;
    email: String;
    mobile: string;
    login_histories: LoginHistory[];
}

declare class Member
{
    private id_: Number;
    private name_: string;
    private email_: String;
    private mobile_: string;
    private login_histories_: LoginHistory[];

    public activate(password: string): boolean;
    public isActivated(): boolean;
    public toJSON(): IMember;
}

declare class LoginHistory
{
    public readonly timestamp: Date;
    public readonly success: Boolean;
}

function main(json: string): void
{
    // Member -> Primitive<ReturnType<Member.prototype.toJSON>>
    let members: Primitive<Member[]> = JSON.parse(json);
    
    // Date -> string throw Date.toJSON()
    console.log(members[0].login_histories[0].timestamp);
}
```

> ```typescript
> type Primitive<Member[]> = Array<{
>     id: number; // Number -> number
>     name: string;
>     email: string; // String -> string
>     mobile: string;
>     login_histories: Array<{
>         timestamp: string; // Date.toJSON(): string
>         success: boolean; // Boolean -> boolean
>     }>;
> }>;
> ```


## Checklist
My suggestion meets these guidelines:

  - [x] This wouldn't be a breaking change in existing TypeScript/JavaScript code
  - [x] This wouldn't change the runtime behavior of existing JavaScript code
  - [x] This could be implemented without emitting different JS based on the types of the expressions
  - [x] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
  - [x] This feature would agree with the rest of [TypeScript's Design Goals](https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals).