打字稿。如何为以下类型创建通用辅助函数?

Typescript. How to create generic helper function for following type?

抱歉,标题不清楚,但我不知道如何快速描述我的问题。

我有一些具有一个文字值的类型和 object 具有这种类型的平面结构作为值(简化版):

type SomeType<T = string> = { value: T };

type SomeTypeMapped = Record<string, SomeType>;

我想写一个 helper(通用)来告诉 TS

const a = helper({
   A: { value: 'literal-1' },
   B: { value: 'literal-2' }
})

具有以下类型:

const a: {
   A: SomeType<"literal-1">;
   B: SomeType<"literal-2">;
}

到目前为止我找到的最接近的解决方案是

function helper<V extends string, K extends string>(val: { [key in K]: SomeType<V> }) {
  return val;
}

const a = helper({
  A: { value: 'asd' }.
  B: { value: 'qwe' }
});

// -->

const a: {
    A: SomeType<"asd" | "qwe">;
    B: SomeType<"asd" | "qwe">;
}

如果我尝试这样修改助手:

function helper<
  V extends string,
  K extends string,
  T extends { [key in K]: SomeType<V> }
>(val: T) {
  return val;
}

它将整个映射转换为常量文字类型:

const a: {
    A: {
        value: "asd";
    };
    B: {
        value: "qwe";
    };
}

这也接近我想要达到的目标,但我的第二点是可读性,因为

const a: {
    A: SomeType<"asd">;
    B: SomeType<"qwe">;
}

对于更复杂的示例(具有比单个 'value' 更多的字段)更具可读性。

我能以某种方式告诉 TS 字段 A 的类型完全是 SomeType<"asd"> 以及字段 B 的类型是 SomeType<"qwe"> 吗?

我会这样写 helper():

const helper = 
  <T extends Record<keyof T, string>>(val: { [K in keyof T]: SomeType<T[K]> }) => val;

您想传递给 SomeTypegeneric type parameter T is a mapping from the keys of val to the associated string literal types。所以目的是当你打电话时

const a = helper({
    A: { value: 'literal-1' },
    B: { value: 'literal-2' }
})

T 将被推断为 { A: "literal-1"; B: "literal-2" }。那么 val 不是直接 T 类型,而是 mapped type {[K in keyof T]: SomeType<T[K]>}.

请注意,编译器确实能够从 {[K in keyof T]: ...T[K]...} 形式的 同态映射类型 的值推断出类型 T。在当前版本的 TS 手册中并不是真的 well-documented,但是手册的 now-deprecated v1 中有一段关于 inference from mapped types 的描述。

无论如何,这意味着当你在上面调用 helper() 时,T 被正确推断,并且 val 被推断为这种类型:

/* const a: {
    A: SomeType<"literal-1">;
    B: SomeType<"literal-2">;
} */

随心所欲。

Playground link to code