【问题标题】:Given tuple type of string constants and tuple type of other types, create object type with string keys and value types给定字符串常量的元组类型和其他类型的元组类型,创建具有字符串键和值类型的对象类型
【发布时间】:2018-12-12 04:20:00
【问题描述】:

我一直在考虑如何为 daggy 之类的东西指定类型,您可以在其中指定数组中的属性名称列表并创建一些构造函数。

基本上,我认为想要这样的东西:

[A, B] with [X, Y] => { [A]: X, [B]: Y }

其中AB 是任意字符串常量类型,XY 是任意类型。例如

['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 的构造函数创建者返回的东西的类型,但我想知道是否有更通用的方法来做到这一点。

【问题讨论】:

    标签: typescript


    【解决方案1】:

    你可以使用交集类型和映射类型来创建你想要的对象:

    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);
    

    【讨论】:

    • 这绝对很时髦,结果对象的签名仍然显示为当然的交集,但它确实为我提供了正确的属性建议以及它们在 VSCode 中的类型,这正是我所需要的。
    猜你喜欢
    • 1970-01-01
    • 2017-06-30
    • 1970-01-01
    • 2020-01-07
    • 2021-07-29
    • 1970-01-01
    • 2011-06-23
    • 2022-10-13
    • 1970-01-01
    相关资源
    最近更新 更多