修复泛型以获取键为元组的对象

时间:2019-11-14 21:55:43

标签: typescript

我需要有关通用Obj[K]的元组的帮助,其中第二项Obj[K][1]是函数。我该如何解决?

export type ThenArg<T> = T extends Promise<infer U> ? U : T

export type FirstArg<T extends any> =
    T extends [infer R, ...any[]] ? R :
    T extends [] ? undefined :
    T;


type Example<Obj, Keys extends Array<keyof Obj>> = {
    [K in Keys[number]]: Obj[K] extends ((...args: any[]) => any) ? FirstArg<ThenArg<ReturnType<Obj[K]>>> : never
}


const Set = {
    alpha: ['skip', () => true]
}

type x = Example<typeof Set, ['alpha']>

/**
 * 
 * looking for x = { alpha: boolean }
 * 
 */

Playground Link

如果Set是一个对象怎么办?会容易吗?

const Set = {
    alpha: {
        keys: ['a', 'b', 'c'],
        fn: () => true
    }
}

2 个答案:

答案 0 :(得分:1)

要解决此问题,需要对Set进行一些更改。如所声明的,Set的项目是string | <some function>联合的数组,这还不够好。

您可以通过几种方法解决此问题,但是最好的方法是在整个对象中添加const assertion

const Set = {
    alpha: ['skip', () => true],
    beta: ['skip', () => Promise.resolve(false)]
} as const

然后您的Example类型可以实现如下:

type MapReturnTypes<
    T extends { [K: string]: readonly [any, (...args: any) => any] }, 
    U extends keyof T
> = {
    [K in U]: ThenArg<ReturnType<T[K][1]>>
}

请注意,现在您将多个键指定为联合而不是数组(MapReturnTypes<typeof Set, 'alpha' | 'beta'>),根据我的经验,这更常见。如果必须要有一个数组,那是一个非常简单的更改:

type MapReturnTypesArray<
    T extends { [K: string]: readonly [any, (...args: any) => any] },
    U extends Array<keyof T>
> = {
    [K in U[number]]: ThenArg<ReturnType<T[K][1]>>
}

我将对正确类型的检查从类型的内部移到了对类型参数的约束,这很明显,如果这些约束不成立,则类型定义不明确。

最后一件事,您可能想从结果类型中删除readonly,这可以通过-readonly完成。

type MapReturnTypes<
    T extends { [K: string]: readonly [any, (...args: any) => any] },
    U extends keyof T
> = {
    -readonly [K in U]: ThenArg<ReturnType<T[K][1]>>
}

答案 1 :(得分:0)

对于对象:

<!DOCTYPE html>
<html>
<head>
	<title>Assignment1_HTML_L2</title>
	
</head>
<body>
   <div id="circle" ondrop="drop(event)" ondragover="allow(event)" >
	<svg width="1000" height="200">
  		<circle id="c1" cx="70" cy="50" r="50" stroke="green" fill="white" stroke-width="4"  style="opacity: 1;" />	

  		<circle cx="200" cy="50" r="50" stroke="yellow"  fill="white" stroke-width="4"  style="opacity: 1;"/>
  	</svg>
  </div>
  <image id="p1" src="https://media.giphy.com/media/l3vR16pONsV8cKkWk/giphy.gif" alt="picture" draggable="true" ondragstart="drag(event)" width="30" height="30" style="opacity: 1;">

</body>
</html>