递归泛型类型来扩展类型 - 奇怪的行为,这是一个错误吗?
Posted
技术标签:
【中文标题】递归泛型类型来扩展类型 - 奇怪的行为,这是一个错误吗?【英文标题】:Recursive generic type to extend types - weird behaviour, is this a bug? 【发布时间】:2019-05-07 08:48:32 【问题描述】:给定一个接口
interface Test
inner:
value: boolean,
还有一个班级
class ContextualData<T>
constructor(public data: T)
我希望能够这样做:
const original: Test =
inner:
value: true,
,
// Wrap the value in a ContextualData object.
original.inner.value = new ContextualData<boolean>(original.inner.value)
我试图通过声明以下类型来实现:
export type Primitive = undefined | null | boolean | string | number | Function
export type Contextuable<T> = T | ContextualData<T>
export type DeepContextuable<T> =
T extends Primitive ? Contextuable<T> : DeepContextuableObject<T>
export type DeepContextuableObject<T> =
[K in keyof T]: DeepContextuable<T[K]>
然后用DeepContextual
改造我的Test
界面:
const original: DeepContextual<Test> =
inner:
value: new ContextualData<boolean>(true),
,
这很好用。
现在,让我们在 ContextualData
类中添加另一个方法:
class ContextualData<T>
constructor(public data: T)
public map<U>(mapFn: (current: T) => U): U
return mapFn(this.data)
即使不使用新函数,我们与 value: ContextualData<boolean>(true)
的上下文接口现在也会引发以下 TS 错误:
TS2322: Type 'ContextualData<boolean>' is not assignable to type
'boolean | ContextualData<true> | ContextualData<false>'.
我错过了什么?这是一个错误吗?
【问题讨论】:
我认为您遇到了这个问题:typescriptlang.org/docs/handbook/release-notes/… ...如果您正在处理string
,您的示例就可以工作,因为这确实是一个原始类型,但因为boolean
实际上是true | false
的联合类型,条件类型将其分配给true
或false
类型的整个变体。因此,如果您将其更改为ContextualData<true>(true)
,它也可以工作(并且Test
类型的内部值也必须是true
类型)。我玩过它,但没有找到解决 boolean
【参考方案1】:
您遇到了条件类型的分配行为。这种(非常有用的)行为表明条件类型分布在裸类型参数的联合成员上。将此与 Typescript 将 boolean
视为 true | false
的事实相结合,我们就明白了。
DeepContextuable<boolean> = DeepContextuable<true | false>
= DeepContextuable<true> | DeepContextuable<false>
= (true | Contextuable<true>) | (false | Contextuable<false>)
= boolean | Contextuable<true> | Contextuable<false
这种行为只发生在裸类型参数上。要禁用它,我们可以将参数放在一个元组中,并且事情会按照您的预期工作。
export type Primitive = undefined | null | boolean | string | number | Function
export type Contextuable<T> = T | ContextualData<T>
export type DeepContextuable<T> =
[T] extends [Primitive] ? Contextuable<T> : DeepContextuableObject<T>
export type DeepContextuableObject<T> =
[K in keyof T]: DeepContextuable<T[K]>
interface Test
inner:
value: boolean,
class ContextualData<T>
constructor(public data: T)
public map<U>(mapFn: (current: T) => U): U
return mapFn(this.data)
const original: DeepContextuable<Test> =
inner:
value: new ContextualData<boolean>(true),
,
【讨论】:
以上是关于递归泛型类型来扩展类型 - 奇怪的行为,这是一个错误吗?的主要内容,如果未能解决你的问题,请参考以下文章
NSManagedObjectContext 扩展中泛型函数中的奇怪 Swift 行为