typescript - 条件类型扩展字符串字面量
我想添加一个类型工具,它应该有条件地添加 T。
查看 Codesandbox
这个想法如下:
类似这样:type IfType<If, Eq, T>
If是一种字符串字面量,例如"Cat" | "Dog"。Eq是If提取的字符串字面量,例如"Cat"或"Dog"T是我想返回的类型,如果传入的泛型类型是那个特定类型的话。
T 扩展了一个 object,但如果 Eq 不是 equal,那么它会返回 Partial<T>,以便类型仍然知道 object 的键(用于解构)。
像这样的东西:
util.ts
type IfType<
If extends string,
Eq extends If,
T extends object
> = If extends Extract<If, Eq> ? T : Partial<T>
otherfile.ts
type Type = 'read' | 'write';
type Props<T extends Type> = {
type: T
} & (
IfType<
T,
// This gets the ts(2344) error, and I don't know how to stop it
"write",
{ descriptionOnlyForWrite: string }
>
| IfType<
T,
// This gets the ts(2344) error, and I don't know how to stop it
"read",
{ hasRead: boolean}
>);
这会产生这个错误:
Type '"write"' does not satisfy the constraint 'T'.
'"write"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Type'.
关于如何输入辅助工具类型有什么建议吗?
额外信息:我通常会在没有 utils 类型的情况下这样输入,这样可以按我想要的方式工作
type Type = 'read' | 'write';
type Props<T extends Type> = {
type: T;
} & (
| (T extends 'write' ? { descriptionOnlyForWrite: string } : { descriptionOnlyForWrite?: undefined })
| (T extends 'read' ? { hasRead: boolean } : { hasRead?: undefined })
);
答案#1
事实是 T extends Type 和 "write" extends Type 并不意味着 "write" extends T。考虑当 T 为 "read"(例如 Props<"read">)时会发生什么;"write" extends "read" 并不成立,因此编译器会报错,提示 IfType<T, "write", XXX> 可能无效。
看起来你并不真的希望 IfType<If, Eq, T> 要求 Eq extends If。假设你不想让 IfType 变得更复杂,你可以直接去掉 Eq 上的约束:
type IfType<
If extends string,
Eq, // <-- no constraint here
T extends object
> = If extends Extract<If, Eq> ? T : Partial<T>
然后以下内容按预期编译:
type Props<T extends Type> = { type: T } & (
IfType<T, "write", { descriptionOnlyForWrite: string }>
| IfType<T, "read", { hasRead: boolean }>
);
如果你真的关心在 If 和 Eq 上表达约束,你将需要将该约束作为单独的类型参数 C 传递给 IfType:
type IfType<
C extends string,
If extends C,
Eq extends C,
T extends object
> = If extends Extract<If, Eq> ? T : Partial<T>
type Props<T extends Type> = { type: T } & (
IfType<Type, T, "write", { descriptionOnlyForWrite: string }>
| IfType<Type, T, "read", { hasRead: boolean }>
);
但我怀疑这对你的使用场景真的有必要。毕竟,IfType 实际上从未使用 C 来计算输出类型;它只是对 If 和 Eq 进行的一种合理性检查。除非你有特别重要的理由这样做,否则我会直接完全移除对 Eq 的约束。
代码的 Playground 链接
