打字稿泛型:使用输出参数类型构建输入参数类型

时间:2019-11-12 07:51:16

标签: javascript angular typescript generics types

我想使用泛型来减少维护,以及维护Typescript类型时出错的可能性。

我有一个名为loadValues的函数,该函数通过以下示例接口接收一个对象:

interface DashboardPreload: {
    studentNames: Observable<string[]>,
    seatNumbers: Observable<number[]>
}

并返回具有以下非常相似的接口的对象。请注意,它具有相同的键,并且键具有相同的值,除了在DashboardPreload中,它包装在Observable中:

interface DashboardState: {
    studentNames: string[],
    seatNumbers: number[] 
}

因此指定类型如下:

function loadValues(preload: DashboardPreload): DashboardState {
    // ...
}

要在各个组件之间重用loadValue函数,我更改了签名以允许使用泛型:

loadValues<A, B>(preload: A): B {
    // ...
}
state = loadValues<DashboardState, DashboardPreload>(toPreload);
// another component would then do
interface UserDetailPreload: {
    name: Observable<string>;
    address: Observable<string>;
}
interface UserDetailState: {
    name: string;
    address: string;
}
otherState = loadValues<UserDetailState, UserDetailPreload>(otherValuesToPreload);

但是我仍然想取得巨大的胜利。我的输入和输出对象

  1. 总是具有相同的键
  2. 和相应的键值类型相同,除了输入对象上的值包装在Observable中。

为避免必须维护非常相似的类型,如果泛型可以指定输入和输出类型之间的上述关系,那就太好了。我只想提供一个通用参数(例如输出),然后以一种可以输入输入和输出的方式编写签名:

// How should this signature look?
function loadValues<P>(preload: ?): P {
    // ...
}
state = loadValues<DashboardState>(toPreload);

这可能吗?函数签名的外观如何(请注意,我并不是在问函数的逻辑,而是在问如何做泛型)。

  1. 诸如Object.entries()之类的东西的打字稿签名
  2. “ K扩展keyof P”之类的结构
  3. 例如https://medium.com/iqoqo-engineering/two-advanced-techniques-to-make-you-a-typescript-wizard-df42e00b1cf8

但尚未找到解决方案。

2 个答案:

答案 0 :(得分:1)

您可以添加如下所示的预加载类型:

type Preload<T> = {
  [P in keyof T]: Observable<T[P]>;
};
function loadValues<P>(preload: Preload<P>): P {
  // ...
}
state = loadValues<DashboardState>(toPreload);

答案 1 :(得分:0)

我不确定我是否理解您要实现的目标,因此这可能无法给出完整的答案,但是也许可以将您推向正确的方向。

如果您也将preload参数的类型设为通用,则typescript应该能够推断出通用返回类型。您需要为此引入一个新的通用接口。

因此,您的函数签名应如下所示:

function loadValues<P>(preload: PreloadState<P>): P {
    // ...
}

interface PreloadState<P> { }

当您像这样使用它时

var preload: PreloadState<DashboardState> = { .. };
var result = loadValues(preload);

result的类型将正确地推断为DashboardState类型。