泛型型别的Typescript数组

lmvvr0a8  于 2022-12-14  发布在  TypeScript
关注(0)|答案(3)|浏览(120)

我想做这样的事情:

type Item<T> = T & {
  func: (v: T) => void
}

function a<What>(...items: Item<What>[]) {}

a({
  name: "",
  func: (v: {name: string}) => {}
}, {
  count: 0,
  func: (v: {count: number}) => {}
})

然而上面的代码会导致一个错误,如何用typscript做类似的事情?

xdyibdwo

xdyibdwo1#

我几乎有它,但我不能得到功能来推断自己的通用,但我分享这无论如何,以防别人可能会解决它,或在情况下,这有助于你。
我使用的技巧是递归地推断What的每个项目,这样What就被正确地处理为元组,并且项目约束被分别应用于What中的每个元素。

type Item<T> =
    T & {func(v:T):void}

type Items<What> =
    What extends [Item<infer A>, ...infer Rest]
    ? [Item<A>,...Items<[...Rest]>]
    : What extends [] ? [] : never

function testFunction<What>(...items: Items<What>) {}

//this works, with an explicit generic
testFunction<[Item<{
    name: string;
}>, Item<{
    count: number;
}>]>({
  name: "",
  func: (v: {name: string}) => {}
}, {
  count: 0,
  func: (v: {count: number}) => {}
})

Playground

ncecgwcz

ncecgwcz2#

您可以使用如下语法:

function a<T extends any[]>(...items: { 
  [K in keyof T]: T[K] & { func: (v: Omit<T[K], 'func'>) => void } 
}) {}

Map类型可以用来Mapitems中的每个元素。T[K]总是表示当前元素,所以我们可以使用它来使自身与函数对象相交。

// ok
a({
  name: "",
  func: (v: { name: string }) => {}
}, {
  count: 0,
  func: (v: { count: number }) => {}
})

// error
a({
  name: 0,
  func: (v: { name: string }) => {} /*
  ~~~~ Types of property 'name' are incompatible 
*/ 
}, {
  count: 0,
  func: (v: { count: number }) => {}
})

对于函数的实现,我建议将所有复杂的泛型内容放在重载中,并为实现函数使用更简单的签名。

function b<T extends any[]>(...items: { 
  [K in keyof T]: T[K] & { func: (v: Omit<T[K], 'func'>) => void } 
}): void
function b(...items: ({ func: (arg: object) => void } & Record<string, any>)[]) {
  for (const item of items) {
    item.func({})
  }
}

Playground

xeufq47z

xeufq47z3#

type Item<T> = T & {
  func: (v: T) => void
}

function a<A extends Item<any>[]>(...items: A) {}

a({
  name: "",
  func: (v: {name: string}) => {}
}, {
  count: 0,
  func: (v: {count: number}) => {}
})
// ^?
// function a<[{
//     name: string;
//     func: (v: {
//         name: string;
//     }) => void;
// }, {
//     count: number;
//     func: (v: {
//         count: number;
//     }) => void;
// }]>(items_0: {
//     name: string;
//     func: (v: {
//         name: string;
//     }) => void;
// }, items_1: {
//     count: number;
//     func: (v: {
//         count: number;
//     }) => void;
// }): void

相关问题