使用泛型,如何从捕获的数组创建对象元组?
Using generics, how can I create a tuple of objects from a captured array?
给出这样的函数:
function makeObjects<T extends string[]>(...values: T);
将 return 值设置为:
T.map(v => ({ [v]: any }));
我正在使用数组映射来显示它在我脑海中的样子,是的,我知道这不是 TS 的工作方式。
您可以使用映射类型 Record
从 T
:
中的值创建类型
function makeObject<T extends string[]>(...values: T): Record<T[number], any>{
return null!
}
let x = makeObject("a", "b", "c")
x.a
x.d // err
我会给它以下调用签名:
declare function makeObjects<T extends string[]>(...values: T):
{ [I in keyof T]: { [P in Extract<T[I], string>]: any } };
(请注意,我还没有实现 makeObjects()
,并认为这超出了问题的范围)。
return 类型 {[I in keyof T]: ...}
是 mapped type over the keys of the generic input type parameter T
. When T
is an array or tuple type, the output type will also be an array or tuple type。
对于输入数组类型 T
中的每个 numeric-like 索引 I
,我们希望使用元素类型 T[I]
作为键类型。为此,您需要使用另一个映射类型,概念上类似于 {[P in T[I]]: any}
,这意味着“一个对象类型,其键为 T[I]
,其值为 any
”。您也可以使用 the Record<K, V>
utility type.
将其表示为 Record<T[I], any>
不幸的是,虽然您只关心 numeric-like 索引,但编译器认为 I
可能是 any key of T
,包括像 "push"
和 "pop"
这样的数组方法名称,因此 属性 类型 T[I]
可能是您不想用作键的各种东西。 (有关此问题的讨论,请参阅 ms/TS#27995)。
解决这个问题的方法是将 T[I]
包装在编译器同意的肯定是 key-like 的内容中。由于您只关心 T[I]
是 string
(因为 T extends string[]
),我们可以使用 the Extract<T, U>
utility type 将 T[I]
过滤为 string-like 事物。
所以这给了你 { [I in keyof T]: { [P in Extract<T[I], string>]: any }}
.
我们来测试一下:
const foo = makeObjects("a", "b", "c");
// const foo: [{ a: any; }, { b: any; }, { c: any; }]
看起来不错;输出类型是对象的元组,其键来自 makeObjects()
.
的相应参数
给出这样的函数:
function makeObjects<T extends string[]>(...values: T);
将 return 值设置为:
T.map(v => ({ [v]: any }));
我正在使用数组映射来显示它在我脑海中的样子,是的,我知道这不是 TS 的工作方式。
您可以使用映射类型 Record
从 T
:
function makeObject<T extends string[]>(...values: T): Record<T[number], any>{
return null!
}
let x = makeObject("a", "b", "c")
x.a
x.d // err
我会给它以下调用签名:
declare function makeObjects<T extends string[]>(...values: T):
{ [I in keyof T]: { [P in Extract<T[I], string>]: any } };
(请注意,我还没有实现 makeObjects()
,并认为这超出了问题的范围)。
return 类型 {[I in keyof T]: ...}
是 mapped type over the keys of the generic input type parameter T
. When T
is an array or tuple type, the output type will also be an array or tuple type。
对于输入数组类型 T
中的每个 numeric-like 索引 I
,我们希望使用元素类型 T[I]
作为键类型。为此,您需要使用另一个映射类型,概念上类似于 {[P in T[I]]: any}
,这意味着“一个对象类型,其键为 T[I]
,其值为 any
”。您也可以使用 the Record<K, V>
utility type.
Record<T[I], any>
不幸的是,虽然您只关心 numeric-like 索引,但编译器认为 I
可能是 any key of T
,包括像 "push"
和 "pop"
这样的数组方法名称,因此 属性 类型 T[I]
可能是您不想用作键的各种东西。 (有关此问题的讨论,请参阅 ms/TS#27995)。
解决这个问题的方法是将 T[I]
包装在编译器同意的肯定是 key-like 的内容中。由于您只关心 T[I]
是 string
(因为 T extends string[]
),我们可以使用 the Extract<T, U>
utility type 将 T[I]
过滤为 string-like 事物。
所以这给了你 { [I in keyof T]: { [P in Extract<T[I], string>]: any }}
.
我们来测试一下:
const foo = makeObjects("a", "b", "c");
// const foo: [{ a: any; }, { b: any; }, { c: any; }]
看起来不错;输出类型是对象的元组,其键来自 makeObjects()
.