gpt4 book ai didi

typescript - 如何声明类型的 "transposed"版本?

转载 作者:行者123 更新时间:2023-12-03 17:43:38 28 4
gpt4 key购买 nike

我想定义一个 TS 函数来将对象转置为数组,例如:

const original  = { 
value: [1, 2, 3],
label: ["one", "two", "three"]
}

const transposed = [
{value: 1, label: "one"},
{value: 2, label: "two"},
{value: 3, label: "three"}
]
然后我想声明一个接收 original 的函数和输出 transposed反之亦然,例如:
function tranpose(original: T): Array<T> // Incorrect, the output should be a transposed version of the object.
如何定义对象的转置版本并正确声明函数?
——
PS 我不是在问实现,只是在问打字和声明。

最佳答案

呵呵,你要Transpose<Transpose<T>>产生类似 T 的东西, 对?而且我假设,虽然在问题中没有明确说明,但您希望它适用于包含对象或数组的任意对象或数组,而不是专门“具有 valuelabel 属性的东西,其中包含数组”。
这在概念上很容易,但在处理对象与数组时事情会变得棘手。即使 mapped types should produce array/tuples from array/tuples ,有些陷阱编译器没有意识到它正在映射数组/元组,直到为时已晚,并且您的映射类型充满了可怕的数组方法,例如 "length" | "push" | "pop" |... .我假设你的实现也会有一些毛毛病,但我担心这里的类型,而不是实现。
这是我的版本,除了 IntelliSense 显示相同类型的联合(例如 type Foo = "a" | "a" | "a" 您希望看到 type Foo = "a" )的一些奇怪之外,它可以工作,幸运的是它不会影响类型的行为方式:

type Transpose<T> =
T[Extract<keyof T, T extends readonly any[] ? number : unknown>] extends
infer V ? { [K in keyof V]: { [L in keyof T]:
K extends keyof T[L] ? T[L][K] : undefined } } : never;

declare function transpose<T>(t: T): Transpose<T>;
解释是我们正在遍历 T 的值/元素类型。找出输出类型的键应该是什么。那应该是 T[keyof T]但我们需要做 T[Extract<keyof T, ...]以确保数组不会把事情搞砸。然后我们大多只是转 T[K][L]进入 T[L][K]在此过程中进行一些类型检查。

让我们测试一下。我们需要一个 const assertion或者类似的东西,如果你想让编译器跟踪哪些值在哪些键上:
const original = {
value: [1, 2, 3],
label: ["one", "two", "three"]
} as const
/* const original: {
readonly value: readonly [1, 2, 3];
readonly label: readonly ["one", "two", "three"];
} */
现在我们将转置它:
const transposed = transpose(original);
/* readonly [{
readonly value: 1;
readonly label: "one";
}, {
readonly value: 2;
readonly label: "two";
}, {
readonly value: 3;
readonly label: "three";
}]
*/


transposed.forEach(v => v.label) // transposed is seen as an array
transposed[1].label // known to be "two"
看起来挺好的。如果您在 transposed 上使用 IntelliSense你会看到它是三个相同类型的联合,但是🤷‍♂️。 (这是 TypeScript 的一个已知设计限制;参见 microsoft/TypeScript#16582 。可以强制编译器积极减少联合,如 here 所示,但这并不是这个问题的真正重点,所以我离题了。)输出类型被视为一个元组,因此它具有我假设您想要的所有数组方法。
然后我们应该能够通过转置转置的东西再次获得原始:
const reOriginal = transpose(transposed);
/* const reOriginal: {
readonly value: readonly [1, 2, 3];
readonly label: readonly ["one", "two", "three"];
} */

reOriginal.label.map(x => x + "!"); // reOriginal.label is seen as an array
再次,看起来不错。 reOriginal的类型是(模 IntelliSense)与 original 的类型相同.万岁!

Playground link to code
Playground link to code with IntelliSense fix

关于typescript - 如何声明类型的 "transposed"版本?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66302996/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com