我正在尝试创建一个映射元组,它可以深入到成员的类型:
export type Argument<T = unknown> = {
value: T;
};
export type TypesOf<T extends Argument[]> = {[Index in keyof T]: T[Index]["value"]};
因此,TypesOf<[{value: number}, {value: string}]>
应该生成[number, string]
。
但是,我得到这个错误:
Type '"value"' cannot be used to index type 'T[Index]'.
编辑:
应用@jcalz的解决方案后的附加问题:
const tuple = [{value: 1}, {value:"foo"}] as const;
type V = TypesOf<typeof tuple>;
I get error:
Type 'readonly [{ readonly value: 1; }, { readonly value: "foo"; }]' does not satisfy the constraint 'Argument<unknown>[]'.
The type 'readonly [{ readonly value: 1; }, { readonly value: "foo"; }]' is 'readonly' and cannot be assigned to the mutable type 'Argument<unknown>[]'.
您所呈现的TypesOf
实现有效,因为TypesOf<[{value: number}, {value: string}]>
确实评估为[number, string]
。数组和元组上的映射类型产生数组和元组。
但是有一个问题,在microsoft/TypeScript#27995中报告,编译器没有意识到在映射类型实现{[I in keyof T]: ...T[I]...}
中I
最终只会成为类似数字的索引。它认为I
可能是"push"
和"pop"
之类的东西,因此T[I]
不能被认为是Argument
:
export type TypesOf<T extends Argument[]> =
{ [I in keyof T]: T[I]["value"] };
// -----------------> ~~~~~~~~~~~~~
// Type '"value"' cannot be used to index type 'T[I]'.
大概这就是你问这个问题的原因吧。GitHub问题被列为一个bug,但它已经开放了很长时间,不清楚这里是否会发生任何事情。
在这种情况下,我倾向于使用Extract<T, U>
实用程序类型来帮助说服编译器某些类型将可分配给另一个类型。如果知道类型T
可以赋值给U
,但编译器不知道,则可以使用Extract<T, U>
代替T
。当稍后指定T
时,如果您对可分配性的判断是正确的,那么Extract<T, U>
将只计算为T
。Extract<T, U>
将被编译器视为可赋值给T
和U
。
在本例中,我们知道T[I]
可以赋值给Argument
,但编译器不知道。因此,以下使用Extract<T[I], Argument>
的解决方案将在不影响TypesOf
输出的情况下抑制编译器错误:
export type TypesOf<T extends Argument[]> =
{ [I in keyof T]: Extract<T[I], Argument>["value"] }; // no error
type Z = TypesOf<[{ value: number }, { value: string }]>;
// type Z = [number, string]
看起来不错!
Playground链接到代码