当从函数的参数声明为泛型时,不会推断函数的返回类型

Returned type of a function is not inferred when it's declared as generic from the function's argument

问题

我有以下两种。

interface SchemaItem {
  name: string,
  value: string
}

type Result<T extends SchemaItem[]> = {
  [K in T[number] as K['name']]: K['value']
}

我有一个函数应该从 SchemaItem[] 参数创建 Result 类型的值。

function createResult<T extends SchemaItem[]>(schemaItems: T): Result<T> {
  // implementation doesn't matter for this question
  return {} as Result<T>
}

当我这样测试时,Result 类型按预期工作。

// ResultType = { foo: "Foo", bar: "Bar" }
type ResultType = Result<[
  { name: 'foo', value: "Foo" },
  { name: 'bar', value: "Bar" },
]>

但是当我用相同的数据测试函数时,返回值没有正确推断。

// result is of type Result<{ name: string; value: string }[]>
const result = createResult([
  { name: 'foo', value: "Foo" },
  { name: 'bar', value: "Bar" },
])

是否可以让 TypeScript 将 result 的类型推断为 { foo: "Foo", bar: "Bar" } 或者这是设计限制?

TS playground

我试过的

我想也许问题在于 SchemaItemname 属性 被声明为 string,这就是我想出的。

interface SchemaItem<T extends string = string> {
  name: T,
  value: string
}

type ArrayToUnion<T> = T extends Array<infer R> ? R : never

type Result<T extends SchemaItem[]> = ArrayToUnion<T> extends SchemaItem<infer R> ? { [key in R]: string } : never

但这并没有帮助,result 值的类型 { [x: string]: string } 也好不到哪儿去。

您可以从 readonly 数组类型扩展您的泛型,然后通过在输入上使用 as const assertion 向函数提供对象文字类型的只读数组。 (使用 as const 断言告诉编译器从字面上推断类型。)

TS Playground

interface SchemaItem {
  name: string,
  value: string
}

type Result<T extends readonly SchemaItem[]> = {
  [K in T[number] as K['name']]: K['value']
}

type ResultType = Result<[
  { name: 'foo', value: "Foo" },
  { name: 'bar', value: "Bar" },
]>

function createResult<T extends readonly SchemaItem[]>(schemaItems: T): Result<T> {
  return {} as Result<T>
}

const result = createResult([
  { name: 'foo', value: "Foo" },
  { name: 'bar', value: "Bar" },
] as const);

result.bar; // "Bar"
result.foo; // "Foo"