【问题标题】:Condition Types extending String Literal扩展字符串文字的条件类型
【发布时间】:2021-09-10 04:50:05
【问题描述】:

我想添加一个类型实用程序,它有条件地应该添加T

Codesandbox

思路如下:

类似这样的:type IfType<If, Eq, T>

  • Ifstring literal 的一种类型,例如 "Cat" | "Dog"
  • EqIf 的提取字符串文字,例如"Cat""Dog"
  • T 是我想要返回的类型,如果传递的 generic type 是那个特定的类型。

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'.

关于如何输入 helper util 类型有什么建议吗?

额外信息:我通常如何在没有 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 })
);

【问题讨论】:

  • 请提供更多您期望和不期望的示例

标签: typescript typescript-generics string-literals type-constraints


【解决方案1】:

T extends Type"write" extends Type 并不意味着"write" extends T。考虑当T"read"(如Props&lt;"read"&gt;)时会发生什么; "write" extends "read" 不是真的,所以编译器抱怨 IfType&lt;T, "write", XXX&gt; 可能无效。

您似乎并不真的希望IfType&lt;If, Eq, T&gt; 要求Eq extends If。假设您不想让IfType 更复杂,您可以删除Eq 上的constraint

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 }>
);

如果您真的关心在IfEq 上表达约束,则需要将该约束作为单独的类型参数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 来计算输出类型;这只是对IfEq 的健全性检查。除非您有一些重要的理由这样做,否则我将完全删除对 Eq 的约束。

Playground link to code

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-26
    • 1970-01-01
    • 2021-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多