我有一个通用的javascript函数,无法在打字稿中正确键入。它需要一组项目。如果这些项目是数组,则将它们展平为单个数组。如果它们是对象,它将它们合并为一个大对象。否则,它仅返回原始数组。
function combineResults(responses) {
if (responses.length === 0) {
return [];
}
if (Array.isArray(responses[0])) {
return responses.flat(1);
} else if (typeof responses[0] === 'object') {
return Object.assign({}, ...responses);
}
else {
return responses;
}
}
是否可以安全地键入此值,以便如果您传递数组数组,则返回类型将是一个数组,如果您传递对象数组,则返回类型将是一个对象。而且,如果您既不传递数组也不传递对象,则返回类型将是原始数组类型。
我倾向于为每种情况提供一个重载的类型签名。这里有一些障碍:一个是您只检查的第一个元素,responses
并假设其余元素属于同一类型;但是数组可以是异构的。而且由于JS和TS中的数组被认为是对象,所以combineResults()
如果您给它一个异构数组(如),则的调用签名可能会做一些奇怪的事情[[1, 2, 3], {a: 1}]
。我不知道您想在运行时在那里发生什么,所以我不知道您想在类型签名中发生什么。这些是极端情况。
另一个障碍是,[{a: 1}, {b: ""}]
在TypeScript中将like这样的数组视为type Array<{a: number, b?: undefined} | {b: string, a?: undefined}>
,并将其转换为{a: number, b: string}
涉及很多类型系统的循环跳跃,包括将并集转换为交集并滤除undefined
属性。
因此,这里是:
type UnionToIntersection<U> =
(U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never
type Defined<T> = T extends any ? Pick<T, { [K in keyof T]-?: T[K] extends undefined ? never : K }[keyof T]> : never;
type Expand<T> = T extends infer U ? { [K in keyof U]: U[K] } : never;
function combineResults<T extends ReadonlyArray<any>>(responses: ReadonlyArray<T>): T[number][];
function combineResults<T extends object>(responses: ReadonlyArray<T>): Expand<UnionToIntersection<Defined<T>>>;
function combineResults<T extends ReadonlyArray<any>>(responses: T): T;
function combineResults(responses: readonly any[]) {
if (responses.length === 0) {
return [];
}
if (Array.isArray(responses[0])) {
return responses.flat(1);
} else if (typeof responses[0] === 'object') {
return Object.assign({}, ...responses);
}
else {
return responses;
}
}
呼叫签名应将数组数组映射到数组,将对象数组映射到对象,并将任何其他数组映射到自身。让我们测试一下:
const arrs = combineResults([[1, 2, 3], ["a", "b"]]); // (string | number)[]
const objs = combineResults([{ a: 1 }, { b: "hey" }]) // {a: number, b: string}
const nons = combineResults([1, 2, 3]); // number[]
我认为看起来不错。但是要注意边缘情况:
const hmm = combineResults([[1, 2, 3], { a: "" }])
/* const hmm: {
[x: number]: number;
a: string;
} ?!?!? */
您可能需要调整这些签名以完全防止异类数组。但这是我现在没有时间继续下去的另一个漏洞。
好的,希望能有所帮助;祝好运!
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句