type AsJSON<T> = | |
T extends Date ? string : | |
T extends Function ? undefined : | |
T extends Symbol ? undefined : | |
T extends Array<any> ? AsJSONArray<T> : | |
T extends object ? AsJSONObj<T> : | |
T; | |
type AsJSONObj<T extends object> = { | |
[K in keyof T]: AsJSON<T[K]> | |
}; | |
type Inspect<T extends Array<any>> = T extends Array<infer X> ? X : never; | |
interface AsJSONArray<T extends Array<any>> extends Array<AsJSON<Inspect<T>>> {} | |
type InvalidKeys<T> = {[K in keyof T]: AsJSON<T[K]> extends undefined ? K : never}[keyof T]; | |
type JSONable<T> = InvalidKeys<T> extends never ? T : ObjectContainsInvalidKeys<InvalidKeys<T>>; | |
type ObjectContainsInvalidKeys<T> = {_:void} | |
type User = { | |
age: number, | |
name: string, | |
hi: ()=> void, | |
createdAt: Date, | |
friends: User[] | |
} | |
function userFromJSON(v: AsJSON<User>): User { | |
return { | |
age: v.age, | |
name: v.name, | |
createdAt: new Date(v.createdAt), | |
hi: ()=>{}, | |
friends: v.friends.map(userFromJSON) | |
} | |
} | |
function safeToJSON<T>(v: JSONable<T>): string { | |
return JSON.stringify(v); | |
} | |
safeToJSON({hi: 1}); | |
safeToJSON({good: 'string'}); | |
safeToJSON({foo: ()=>{}, bar: 1}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment