英文:
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<I extends Inner> = { f: I }
interface Bar<I extends Inner> {
b: I
}
type O<I extends Partial<Inner>> = Foo<Required<I>> & Bar<Required<I>
But the code above doesn't compile with the following error:
Type 'Required<I>' does not satisfy the constraint 'Inner'.
Types of property 'a' are incompatible.
Type 'I["a"]' is not assignable to type 'string'.
Type 'string | undefined' is not assignable to type 'string'.
Type 'undefined' is not assignable to type 'string'.ts(2344)
I'm expecting that Required<Partial<Inner>>
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>>;
如何修复它,如果可以的话,以类型安全的方式,将非常具体于您的实际情况。例如,诱人的做法是:
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<Inner>
means that I
can be a subtype of Partial<Inner>
, and there are subtypes of Partial<Inner>
that — even passed through Required
— aren't type-compatible with the I extends Inner
constraint on Foo
. Here's an example of one such type:
type Incompatible = Partial<Inner> & {a: undefined};
That's a valid subtype of Partial<Inner>
, because the definition of Partial<Inner>
is {a?: string | undefined}
. But Required<Incompatible>
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<Required<Incompatible>>;
How you fix it — if you can, in a type-safe way — will be very specific to your real situation. For instance, it's tempting to do:
type RequiredInner<T extends Partial<Inner>> = {
[Key in keyof T]: T[Key] extends undefined ? Key extends keyof Inner ? Inner[Key] : never : T[Key];
};
...and then use Foo<RequiredInner<I>>
. 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<Inner>
. 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论