Required> doesn’t extend Inner

huangapple go评论65阅读模式
英文:

Required<Partial<Inner>> doesn't extends Inner

问题

类型 'Required<I>' 不能满足约束 'Inner'
  属性 'a' 的类型不兼容。
    类型 'I["a"]' 不能分配给类型 'string'
      类型 'string | undefined' 不能分配给类型 'string'
        类型 'undefined' 不能分配给类型 'string'
英文:

I have a code similar to the following one:

type Inner = {
  a: string
}
type Foo&lt;I extends Inner&gt; = { f: I }
interface Bar&lt;I extends Inner&gt; {
  b: I
}
type O&lt;I extends Partial&lt;Inner&gt;&gt; = Foo&lt;Required&lt;I&gt;&gt; &amp; Bar&lt;Required&lt;I&gt;

Playground link

But the code above doesn't compile with the following error:

Type &#39;Required&lt;I&gt;&#39; does not satisfy the constraint &#39;Inner&#39;.
  Types of property &#39;a&#39; are incompatible.
    Type &#39;I[&quot;a&quot;]&#39; is not assignable to type &#39;string&#39;.
      Type &#39;string | undefined&#39; is not assignable to type &#39;string&#39;.
        Type &#39;undefined&#39; is not assignable to type &#39;string&#39;.ts(2344)

I'm expecting that Required&lt;Partial&lt;Inner&gt;&gt; extends Inner.

答案1

得分: 3

以下是您要翻译的内容:

问题在于I extends Partial<Inner>表示I可以是Partial<Inner>子类型,并且有一些Partial<Inner>的子类型,即使经过Required处理,也与Foo上的I extends Inner约束不兼容。以下是一个这样的类型示例:

type Incompatible = Partial<Inner> & {a: undefined};

这是Partial<Inner>的有效子类型,因为Partial<Inner>的定义是{a?: string | undefined}。但是,Required<Incompatible>并不会将其转换为扩展Inner的东西,它只会将其转换为{a: undefined}。如果您尝试像这样在Foo中使用它,它将因与您的映射类型失败的相同原因而失败:

type Q = Foo<Required<Incompatible>>;

Playground链接

如何修复它,如果可以的话,以类型安全的方式,将非常具体于您的实际情况。例如,诱人的做法是:

type RequiredInner<T extends Partial<Inner>> = {
    [Key in keyof T]: T[Key] extends undefined ? Key extends keyof Inner ? Inner[Key] : never : T[Key];
};

然后使用Foo<RequiredInner<I>>。尽管这样可以工作,但它做出了一个重大的假设,可能不是合理的:您在具有Partial<Inner>的地方没有运行时值{a: undefined}。这个假设不是类型安全的。(但是jcalz指出在问题的评论中,使用exactOptionalPropertyTypes选项可能会阻止这种赋值,尽管该标志不能解决您的问题。)所以我认为我们不能为您的实际代码提供一般的解决方法。但希望理解问题将有助于您解决它。

英文:

The issue is that I extends Partial&lt;Inner&gt; means that I can be a subtype of Partial&lt;Inner&gt;, and there are subtypes of Partial&lt;Inner&gt; that&nbsp;&mdash; even passed through Required&nbsp;&mdash; aren't type-compatible with the I extends Inner constraint on Foo. Here's an example of one such type:

type Incompatible = Partial&lt;Inner&gt; &amp; {a: undefined};

That's a valid subtype of Partial&lt;Inner&gt;, because the definition of Partial&lt;Inner&gt; is {a?: string | undefined}. But Required&lt;Incompatible&gt; doesn't turn it back into something that extends Inner, it just turns it into {a: undefined}. If you try to use that with Foo like this, it fails for the same reason your mapped type fails:

type Q = Foo&lt;Required&lt;Incompatible&gt;&gt;;

Playground link

How you fix it&nbsp;&mdash; if you can, in a type-safe way&nbsp;&mdash; will be very specific to your real situation. For instance, it's tempting to do:

type RequiredInner&lt;T extends Partial&lt;Inner&gt;&gt; = {
    [Key in keyof T]: T[Key] extends undefined ? Key extends keyof Inner ? Inner[Key] : never : T[Key];
};

...and then use Foo&lt;RequiredInner&lt;I&gt;&gt;. And although that works, it makes a major assumption which may not be sound: That you don't have a runtime value of {a: undefined} where you have that Partial&lt;Inner&gt;. That assumption isn't typesafe. (But jcalz points out in a comment on the question that using the exactOptionalPropertyTypes option could prevent that assignment, though that flag doesn't solve your problem.) So I don't think we can give you a general way to solve it in your real code. But hopefully understanding the problem will help you solve it.

huangapple
  • 本文由 发表于 2023年5月24日 20:34:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/76323601.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定