我一直在考虑如何为daggy之类的类型指定类型,在其中您可以在数组中指定属性名称列表,并创建一些构造函数。
本质上,我认为想要这样的东西:
[A, B] with [X, Y] => { [A]: X, [B]: Y }
其中A
和B
是任意字符串常量类型,而X
和Y
是任何类型。例如
['x', 'y'] with [string, number] => { x: string, y: number }
鉴于目标daggy的使用,目标界面可能最终会像
<K0 extends string, K1 extends string>(keys: [K0, K1])
=> <V0, V1>(v0: V0, v1: V1)
=> { [K0]: V0, [K1]: V1 }
我注意到有一点很有效,那就是TS似乎接受[K in NS[number]: ...
和[K in K0|K1]
是有效的。预期效果如下:
function point<
A extends string,
B extends string
>(names: [A, B]): { [K in A|B]: number };
function point(names: any[]): { [x: string]: number } {
return {
[names[0]]: 0,
[names[1]]: 0,
};
}
const p0 = point(['a', 'b']);
// :: { a: number, b: number }
但是,在这种情况下,您不能假设联盟成员的迭代顺序,也无法将这些成员与另一个联盟的成员压缩在一起。
但是,如果我尝试直接使用K extends string
类型,就像这样:
function createZip2Object<
K0 extends string,
K1 extends string
>(names: [K0, K1]): <V0, V1>(v0: V0, v1: V1) => { [K0]: V0, [K1]: V1 };
function createZip2Object(names: [string, string]): { [x: string]: any } {
return (...args) => ({
[names[0]]: args[0],
[names[1]]: args[1],
});
}
const point = createZip2Object(['x', 'y']);
const p0 = point(10, 945);
我收到消息A computed property name in a type literal must refer to an expression whose type is a literal type or a 'unique symbol' type.
和'K0' only refers to a type, but is being used as a value here.
即使没有在内部函数中隐藏类型参数的简单示例,也会出现此错误消息:
function boxValue<K extends string, V>(k: K, v: V): { [K]: V } {
return { [k]: v };
}
const bv = boxValue('v', 42);
// :: {}
这发生在Typescript playground和带有Typescript 2.9.1的VSCode中。
我知道我可以手动指定daggy的构造函数创建者返回的内容的类型,但是我想知道是否存在更通用的方法。
答案 0 :(得分:2)
您可以使用相交类型和映射类型来创建所需的对象:
function createZip2Object<
K0 extends string,
K1 extends string
>(names: [K0, K1]): <V0, V1>(v0: V0, v1: V1) => { [P in K0]: V0 } & { [P in K1]: V1 };
function createZip2Object(names: [string, string]): { [x: string]: any } {
return (...args: any[]) => ({
[names[0]]: args[0],
[names[1]]: args[1],
});
}
const point = createZip2Object(['x', 'y']);
const p0 = point(10, 945);