我有一个类似于下面的代码:
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>
Playground链接
但是上面的代码无法编译,并出现以下错误:
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)
我期望Required<Partial<Inner>>
扩展Inner
。
1条答案
按热度按时间thtygnil1#
问题是
I extends Partial<Inner>
意味着I
可以是Partial<Inner>
的 * 子类型 *,并且存在Partial<Inner>
的子类型-即使通过Required
-也与Foo
上的I extends Inner
约束不兼容。下面是一个此类类型的示例:这是
Partial<Inner>
的有效子类型,因为Partial<Inner>
的定义是{a?: string | undefined}
。但是Required<Incompatible>
并没有把它变回Inner
的扩展,它只是把它变成了{a: undefined}
。如果你尝试像这样对Foo
使用它,它会失败,原因和你的Map类型失败的原因一样:Playground链接
如果可以的话,以类型安全的方式修复它,这将非常具体地针对您的真实的情况。例如,它很容易做到:
...然后使用
Foo<RequiredInner<I>>
。虽然这是可行的,但它做出了一个主要的假设,这个假设可能不合理:你没有{a: undefined}
的运行时值,而你有Partial<Inner>
。这个假设不是类型安全的。(但是jcalz在关于这个问题的评论中指出,使用exactOptionalPropertyTypes
选项可能会阻止这种赋值,尽管这个标志并不能解决你的问题。)所以我认为我们不能给予你一个通用的方法来在你的真实的代码中解决这个问题。但希望理解这个问题能帮助你解决它。