awesome-typescript
awesome-typescript copied to clipboard
「重学TS 2.0 」TS 练习题第二十二题
实现一个 RequireAtLeastOne
工具类型,它将创建至少含有一个给定 Keys
的类型,其余的 Keys
保持原样。具体的使用示例如下所示:
type Responder = {
text?: () => string;
json?: () => string;
secure?: boolean;
};
type RequireAtLeastOne<
ObjectType,
KeysType extends keyof ObjectType = keyof ObjectType,
> = // 你的实现代码
// 表示当前类型至少包含 'text' 或 'json' 键
const responder: RequireAtLeastOne<Responder, 'text' | 'json'> = {
json: () => '{"message": "ok"}',
secure: true
};
请在下面评论你的答案。
type Responder = {
text?: () => string;
json?: () => string;
secure?: boolean;
};
type RequireAtLeastOne<
ObjectType,
KeysType extends keyof ObjectType = keyof ObjectType,
> = KeysType extends unknown ? Responder & {[K in KeysType]-?: ObjectType[K]}: never;// 你的实现代码
// 表示当前类型至少包含 'text' 或 'json' 键
const responder: RequireAtLeastOne<Responder, 'text' | 'json'> = {
json: () => '{"message": "ok"}',
secure: true
};
// @ts-expect-error 因为没有'text'和'json'中的任何一个,报错
const responder2: RequireAtLeastOne<Responder, 'text' | 'json'> = {
secure: true
};
额外增加了一个测试用例。
type Responder = {
text?: () => string;
json?: () => string;
secure?: boolean;
};
type RequireAtLeastOne<ObjectType, KeysType extends keyof ObjectType = keyof ObjectType> = {
[K in keyof ObjectType]: K extends KeysType ? Responder & Required<Pick<Responder, K>> : never;
}[keyof ObjectType];
// 表示当前类型至少包含 'text' 或 'json' 键
const responder: RequireAtLeastOne<Responder, "text" | "json"> = {
json: () => '{"message": "ok"}',
secure: true,
};
type Responder = {
text?: () => string;
json?: () => string;
secure?: boolean;
};
type RequireAtLeastOne<
ObjectType,
KeysType extends keyof ObjectType = keyof ObjectType,
> = KeysType extends keyof ObjectType ?
ObjectType & Required<Pick<ObjectType, KeysType>>:
never;
// 表示当前类型至少包含 'text' 或 'json' 键
const responder: RequireAtLeastOne<Responder, 'text' | 'json'> = {
json: () => '{"message": "ok"}',
secure: true
};
const responder2: RequireAtLeastOne<Responder, 'text' | 'json'> = {
secure: true
};
const responder3: RequireAtLeastOne<Responder, 'text' | 'json'> = {
};
type Responder = {
text?: () => string;
json?: () => string;
secure?: boolean;
ee: number
};
type SetRequired<T, K extends keyof T> = Required<Pick<T, K>>;
type GetAtleast<ObjectType, KeysType extends keyof ObjectType> =
KeysType extends infer A | infer B ?
Required<Pick<ObjectType, KeysType>> | SetRequired<ObjectType, A> | SetRequired<ObjectType, B>:
never;
type RequireAtLeastOne<
ObjectType,
KeysType extends keyof ObjectType = keyof ObjectType,
> = GetAtleast<ObjectType, KeysType> & Omit<ObjectType, KeysType>;
// 表示当前类型至少包含 'text' 或 'json' 键
const responder: RequireAtLeastOne<Responder, 'text' | 'json'> = {
// json: () => '{"message": "ok"}',
text: () => '{"message": "ok"}',
secure: true,
ee: 2
};
type Responder = {
text?: () => string
json?: () => string
secure?: boolean
}
type RequireAtLeastOne<
ObjectType,
KeysType extends keyof ObjectType = keyof ObjectType,
> = KeysType extends KeysType ? Required<Pick<ObjectType, KeysType>> & Omit<ObjectType, KeysType> : never
type T1 = RequireAtLeastOne<Responder, 'text' | 'json'>
// 表示当前类型至少包含 'text' 或 'json' 键
const responder: T1 = {
json: () => '{"message": "ok"}',
secure: true
}
const responder2: T1 = {
text: () => '{"message": "ok"}',
secure: true
}
const responder3: T1 = {
json: () => '{"message": "ok"}',
text: () => '{"message": "ok"}',
secure: true
}
const responder4: T1 = {
json: () => '{"message": "ok"}',
}
const responder5: T1 = {
text: () => '{"message": "ok"}',
}
const responder6: T1 = { // Error
secure: true
}
// 实现一个 RequireAtLeastOne 工具类型,它将创建至少含有一个给定 Keys 的类型,其余的 Keys 保持原样。具体的使用示例如下所示:
type Responder = {
text?: () => string;
json?: () => string;
secure?: boolean;
};
type RequireAtLeastOne<
ObjectType,
KeysType extends keyof ObjectType = keyof ObjectType,
> = KeysType extends any
? Omit<ObjectType, KeysType> & Required<Pick<ObjectType, KeysType>>
: never
思路: 这里利用了联合类型作为泛型是 extends 会分发处理的特性,之后将去掉某个属性的类型与只有某个属性,且必填的类型做交叉合并
type Responder = {
text?: () => string;
json?: () => string;
secure?: boolean;
};
type RequireAtLeastOne<
ObjectType,
KeysType extends keyof ObjectType = keyof ObjectType,
> = KeysType extends keyof ObjectType ? ObjectType & Required<Pick<ObjectType, KeysType>> : never
// 表示当前类型至少包含 'text' 或 'json' 键
const responder: RequireAtLeastOne<Responder, 'text' | 'json'> = {
json: () => '{"message": "ok"}',
secure: true
};
type RequireAtLeastOne<
ObjectType,
KeysType extends keyof ObjectType = keyof ObjectType
> = KeysType extends string
? { [P in KeysType]: ObjectType[P] } & Omit<ObjectType, KeysType>
: never;
// 表示当前类型至少包含 'text' 或 'json' 键
const responder: RequireAtLeastOne<Responder> = {
json: () => '{"message": "ok"}',
secure: true
};
type Responder = {
text?: () => string;
json?: () => string;
secure?: boolean;
};
type RequireAtLeastOne<
ObjectType,
KeysType extends keyof ObjectType = keyof ObjectType,
> = Omit<ObjectType, KeysType> & {
[k in KeysType]: Required<Pick<ObjectType, k>>
}[KeysType]// 你的实现代码
// 表示当前类型至少包含 'text' 或 'json' 键
const responder: RequireAtLeastOne<Responder, 'text' | 'json'> = {
json: () => '{"message": "ok"}',
secure: true
};
哪位大佬能解释下 KeysType extends keyof ObjectType = keyof ObjectType
这句话是什么意思?
// 21
type Responder = {
text?: () => string;
json?: () => string;
secure?: boolean;
};
type RequireAtLeastOne<
ObjectType,
KeysType extends keyof ObjectType = keyof ObjectType,
> = { [P in KeysType]-?: ObjectType[P] } & ObjectType;
// 表示当前类型至少包含 'text' 或 'json' 键
const responder: RequireAtLeastOne<Responder, 'text' | 'secure'> = {
json: () => '{"message": "ok"}',
secure: true
};
联合类型分散后再进行联合
type Responder = {
text?: () => string;
json?: () => string;
secure?: boolean;
};
type RequireAtLeastOne<
ObjectType,
KeysType extends keyof ObjectType = keyof ObjectType,
> =
KeysType extends KeysType
? Required<Pick<ObjectType, KeysType>> & Omit<ObjectType, KeysType>
: never
type X = RequireAtLeastOne<Responder, 'text' | 'json'>
哪位大佬能解释下
KeysType extends keyof ObjectType = keyof ObjectType
这句话是什么意思?
这不是对传入的第二个类型参数做一个泛型约束吗,表示只能传第一个类型的key组成的联合类型的父类型,也就是你传入的第二个类型参数,必须是联合类型,且必须由第一个类型的key组成,默认为全部的key
平安已经收到你的邮件啦
这是来自QQ邮箱的假期自动回复邮件。您好,我最近正在休假中,无法亲自回复您的邮件。我将在假期结束后,尽快给您回复。
[K in KeysType]-?
"-" 这个符号是什么意思哦
[K in KeysType]-?
"-"这个符号是什么英文哦
就是 减去可选,变成必选
这是来自QQ邮箱的假期自动回复邮件。您好,我最近正在休假中,无法亲自回复您的邮件。我将在假期结束后,尽快给您回复。
为什么看上去不对,答案却是对的?
分开操作 意思明明是 text 和 json 都必须有???
这是来自QQ邮箱的假期自动回复邮件。您好,我最近正在休假中,无法亲自回复您的邮件。我将在假期结束后,尽快给您回复。
type RequireAtLeastOne<ObjectType, KeysType extends keyof ObjectType = keyof ObjectType> = Omit<ObjectType, KeysType> &
(KeysType extends keyof ObjectType ? Required<Pick<ObjectType, KeysType>> : never);
这是来自QQ邮箱的假期自动回复邮件。您好,我最近正在休假中,无法亲自回复您的邮件。我将在假期结束后,尽快给您回复。
type Responder = {
text?: () => string
json: () => string
secure?: boolean
password: string
}
type Merge<Obj extends Record<string, any>> = Obj extends any
? {
[Key in keyof Obj]: Obj[Key]
}
: never
type RequireAtLeastOne<T extends Record<string, any>, K extends keyof T = keyof T> = Exclude<
{
[Key in K]: Merge<
{
[Key2 in Key]: Exclude<T[Key2], undefined>
} & {
[Key3 in Exclude<keyof T, K>]: T[Key3]
}
>
}[K],
undefined
>
type TTestRequireAtLeastOne = RequireAtLeastOne<Responder, 'text' | 'json'>
const responder: TTestRequireAtLeastOne = {
json: () => '{"message": "ok"}',
secure: true,
password: '',
}
这是来自QQ邮箱的假期自动回复邮件。您好,我最近正在休假中,无法亲自回复您的邮件。我将在假期结束后,尽快给您回复。
为什么看上去不对,答案却是对的?
分开操作 意思明明是 text 和 json 都必须有???
因为在typescript中有一个条件分布的概念,条件分布的规则主要是在泛型、类型参数等地方应用的,所以当你把text | json 当做泛型参数传入某个类型的时候,其实typescript会把它每个成员拆解开来进行条件判断,也就是KeysType第一次是text,第二次是json
这是来自QQ邮箱的假期自动回复邮件。您好,我最近正在休假中,无法亲自回复您的邮件。我将在假期结束后,尽快给您回复。
RequireAtLeastOne 返回的是联合类型
{
text: () => string;
json?: () => string;
secure?: boolean;
} | {
text?: () => string;
json: () => string;
secure?: boolean;
}```
这是来自QQ邮箱的假期自动回复邮件。您好,我最近正在休假中,无法亲自回复您的邮件。我将在假期结束后,尽快给您回复。