0

简而言之:

如何使用 Typescript 类型的系统声明一个作为类型参数的泛型接口

  • 组的一种类型G(属于一个组的所有属性)
  • 组中某个项目的类型I(一个项目的所有属性,其中一个组有几个)
  • N中的一种属性类型G,它的值是该组G[N]的项目数组I[]

并让生成的接口类型是一个组 G,其属性 N 被键入到项目 I 的数组中,同时在生成的类型中还包括 G 的所有其他属性。



到目前为止我尝试过的

修订 #2(成功)

在阅读了一些关于计算索引类型(正确的名称?)及其局限性之后,我想出了这种方法:

type GroupOfItems<Group, Item, GroupOn extends keyof Group> = {
    [n in GroupOn]: Item[];
}
type A = {a: any, children: B[]};
type B = {b: number};

let obj: GroupOfItems<A, B, 'children'> & Omit<A, 'children'>;

我使用联合类型来组合通用“组”接口和“其他”属性,从而产生我想要的结构的完全类型检查对象。在这个操场上看看

修订 #1

第一个答案告诉我我有一个语法错误。它提供了一个具有 3 个类型参数的有效接口。但是,生成的类型缺少项目数组以外的任何组属性。

我的下一次尝试,似乎是无效的打字稿(见操场):

type GroupOfItems<Group, Item, GroupProp extends keyof Group> = {
    [OtherProp in keyof Omit<Group, GroupProp>]: Group[OtherProp];
    [n in GroupProp]: Item[];
}

我天真的第一次尝试:


interface GroupOfItems<GroupType, ItemType, NameOfItemsProp extends keyof G> {
    [key: NameOfItemsProp]: ItemType[];
}

但是,正如您在这个 TS Playground中看到的那样,Typescript 编译器对此并不满意,我想不出办法。

这个结构的具体用法

假设以下类型

    interface Movie {  // An example Item
        id: number,
        title: string,
        releaseYear: number,
        // ... more movie properties
    }

    interface MovieList {  // An example Group
        id: number,
        description: string,        
        // ... more list properties
        movies: Movie[], // This property holds the group of items
    }

已定义,我想创建一个泛型类型GroupOfItems<MovieList, Movie, 'movies'>,该类型应映射到类似的结构

{ 
    id: 0,
    description: 'A collection of funny movies'
    totalRuntimeInSecs: 9815,
    // ... all other movielist properties
    movies: [
        {
            id: 0,
            title: 'Blazing Saddles',
            releaseYear: 1974,
            // ... 
        }
    ]
}

但是,我也希望具体类型GroupOfItems<Playlist, Song, 'songs'> (假设PlaylistSong定义)与

{
    playlistId: 0,
    playlistName: string,
    playlistDescription: string,
    //... more playlist props
    songs: Song[]  // This property holds the item array
}

提问的动机

我正在尝试实现一个通用数据源类,该类可以对其数据进行分组并切换项目组的可见性。虽然输入数据的结构是不变的,但保存组项目的属性名称在现有接口中可能不同。

4

1 回答 1

1

这是你要找的吗?

interface Movie {  // An example Item
    id: number,
    title: string,
    releaseYear: number,
    // ... more movie properties
}

interface MovieList {  // An example group
    id: number,
    description: string,
    // ... more list properties
    movies: Movie[], // This property holds the item array
}

type GroupOfItems<Group, Item, GroupOn extends keyof Group> = {
    [key in GroupOn]: Item[];
}

const obj: GroupOfItems<MovieList, Movie, 'movies'> = {
    id: 0,
    description: 'A collection of funny movies',
    movies: [
        {
            id: 0,
            title: 'Blazing Saddles',
            releaseYear: 1974,
        }
    ]
};
于 2020-03-26T20:26:37.463 回答