awesome-typescript
awesome-typescript copied to clipboard
「重学TS 2.0 」TS 练习题第四十五题
实现 JsonifiedObject
工具类型,用于对 object
对象类型进行序列化操作。具体的使用示例如下所示:
type JsonifiedObject<T extends object> = // 你的实现代码
type MyObject = {
str: "literalstring",
fn: () => void,
date: Date,
customClass: MyClass,
obj: {
prop: "property",
clz: MyClass,
nested: { attr: Date }
},
}
declare class MyClass {
toJSON(): "MyClass";
}
/**
* type JsonifiedMyObject = {
* str: "literalstring";
* fn: never;
* date: string;
* customClass: "MyClass";
* obj: JsonifiedObject<{
* prop: "property";
* clz: MyClass;
* nested: {
* attr: Date;
* };
* }>;
* }
*/
type JsonifiedMyObject = Jsonified<MyObject>;
declare let ex: JsonifiedMyObject;
const z1: "MyClass" = ex.customClass;
const z2: string = ex.obj.nested.attr;
请在下面评论你的答案
declare class MyClass {
toJSON(): "MyClass";
}
type sss = never extends void ? true : false;
type Jsonified<T extends object> = {
[K in keyof T]: T[K] extends { toJSON(): infer Return }
? ReturnType<T[K]["toJSON"]>
: T[K] extends (...arg: any[]) => any
? never
: T[K] extends object
? Jsonified<T[K]>
: T[K];
};
type MyObject = {
str: "literalstring";
fn: () => void;
date: Date;
customClass: MyClass;
obj: {
prop: "property";
clz: MyClass;
nested: { attr: Date };
};
};
/**
* type JsonifiedMyObject = {
* str: "literalstring";
* fn: never;
* date: string;
* customClass: "MyClass";
* obj: JsonifiedObject<{
* prop: "property";
* clz: MyClass;
* nested: {
* attr: Date;
* };
* }>;
* }
*/
type JsonifiedMyObject = Jsonified<MyObject>;
declare let ex: JsonifiedMyObject;
const z1: "MyClass" = ex.customClass;
const z2: string = ex.obj.nested.attr;
type Jsonified<T extends object> = {
[k in keyof T]: T[k] extends object
? "toJSON" extends keyof T[k]
? T[k]["toJSON"] extends (...args: any[]) => infer R
? R
: never
: T[k] extends (...args: any[]) => any
? never
: Jsonified<T[k]>
: T[k];
};
type MyObject = {
str: "literalstring";
fn: () => void;
date: Date;
customClass: MyClass;
obj: {
prop: "property";
clz: MyClass;
nested: { attr: Date };
};
}
declare class MyClass {
toJSON(): "MyClass";
}
/**
* type JsonifiedMyObject = {
* str: "literalstring";
* fn: never;
* date: string;
* customClass: "MyClass";
* obj: JsonifiedObject<{
* prop: "property";
* clz: MyClass;
* nested: {
* attr: Date;
* };
* }>;
* }
*/
type JsonifiedMyObject = Jsonified<MyObject>;
declare let ex: JsonifiedMyObject;
const z1: "MyClass" = ex.customClass;
const z2: string = ex.obj.nested.attr;
思路: 比较费事儿一些,要枚举所有可能遇到的情况,测试用例对于function类型没有详细说明,我按照never统一输出的。如果需要考虑函数的返回值的话,多一层 extends 判断。
type Jsonified<T extends object> = { [K in keyof T]: changeType<T[K]> }
type changeType<T> = [T] extends [string] ? T : T extends (...args: any) => infer R ? R & 1 : T extends Date ? string : T extends { toJSON(): infer C } ? C : T extends object ? { [K in keyof T]: T[K] extends { toJSON(): infer C } ? C : changeType<T[K]> } : false
type Jsonified<T> = T extends Date
? string
: T extends MyClass
? "MyClass"
: T extends () => void
? never
: T extends object
? {
[K in keyof T]: Jsonified<T[K]>;
}
: T;