TypeScript中对象文字的动态泛型类型推断

时间:2018-05-24 12:51:34

标签: javascript typescript object generics types

在typescript中,我可以像这样声明一个泛型函数:

const fn: <T>(arg: T)=>Partial<T>

在这种情况下,TypeScript有时可以根据我传递的实际参数推断函数的类型参数。是否有类似的方法来定义一个通用对象文字,其类型参数可以根据其内容动态推断?类似的东西:

interface XYZ { 
  obj: <T>{ arr: T[], dict: Partial<T> }
}

我知道我可以像以下那样使整个界面变得通用:

interface XYZ<T> {
  arr: T[],
  dict: Partial<T>
}

但我想避免这种情况,因为每当我使用该接口时,我都必须提前声明泛型类型。例如

const x: XYZ

不起作用。如果我想使声明一般,我不得不写:

const x: XYZ<any>

但是这不允许TypeScript根据x的实际内容动态推断特定的泛型类型

2 个答案:

答案 0 :(得分:2)

啊,您需要Microsoft/TypeScript#17574中讨论的通用值。如您所知,除通用函数外,它们不存在于语言中。如果你愿意,你可以去解决这个问题,如果你觉得它有用,可以讨论你的用例。

给定通用接口

interface XYZ<T> {
  arr: T[],
  dict: Partial<T>
}

我只想使用此解决方法:创建一个通用函数来验证某些 XYZ<T>的值是T,并允许类型推断实际推断{{1只要有必要。切勿尝试声明T类型的内容。像这样:

XYZ

以上通常在实践中对我有用。专业人士认为它是“自然的”TypeScript。 con是它不代表“我不关心什么类型const asXYZ = <T>(xyz: XYZ<T>) => xyz; const x = asXYZ({ arr: [{ a: 1, b: 2 }, { a: 3, b: 4 }], dict: { a: 1300 } }); // becomes XYZ<{a: number, b: number}> 是正确的。”

如果您真的想要,可以定义existential type。 TypeScript本身不支持这些,但有一种方法可以表示它:

T

interface SomeXYZ { <R>(processXYZ: <T>(x: XYZ<T>) => R): R } const asSomeXYZ = <T>(xyz: XYZ<T>): SomeXYZ => <R>(processXYZ: <T>(x: XYZ<T>) => R) => processXYZ(xyz); 类型是一种具体类型,不再关心SomeXYZ,但对某些 T保留对T的引用。您使用XYZ<T>从对象创建一个:

asSomeXYZ

您可以通过传递处理保持引用的函数来使用它。该功能必须为const someXYZ: SomeXYZ = asSomeXYZ({ arr: [{ a: 1, b: 2 }, { a: 3, b: 4 }], dict: { a: 1300 } }); // SomeXYZ 的任何XYZ<T>做好准备,因为您不知道T T持有的SomeXYZ类型。

// use one
const xyzArrLength = someXYZ((xyz => xyz.arr.length))

xyzArrLengthnumber,因为无论xyz => xyz.arr.length是什么,函数number都会返回T

TypeScript中的存在类型很尴尬,因为正在进行大量的控制反转。这是这个的主要缺点,以及为什么我通常会选择我首先提出的不那么完美但更容易思考的解决方法。

希望有所帮助。祝你好运!

编辑:重新阅读你的问题让我觉得你实际上是在寻求我列为“解决方法”的答案。那么,呃......用那个?欢呼声。

答案 1 :(得分:1)

interface MyGenericObjectLiteral<T> {
  arr: T[],
  dict: Partial<T>
}

interface XYZ { 
    obj: MyGenericObjectLiteral<any>
}

这里的接口XYZ不是通用的,只是子对象MyGenericObjectLiteral。它实际上就是你想要的,除了它的语法有点不同。