首页 > 解决方案 > TypeScript 泛型类型参数是用函数推断的,但不是类型?

问题描述

考虑一下:

type SpecificKeys<T extends string> = {
  [key in T]: string;
};

const foobar: SpecificKeys<"foo" | "bar"> = {
  foo: "foo",
  bar: "bar",
};

我必须在创建时将键的并集指定为泛型类型参数foobar,这是多余的。我想不出任何办法。但如果我写一个无所事事的函数:

function makeSpecificKeys<T extends string>(thing: SpecificKeys<T>): SpecificKeys<T> {
  return thing;
}

const foobarInferred = makeSpecificKeys({
  foo: "foo",
  bar: "bar",
});

然后 constfoobarInferred被正确键入,SpecificKeys<"foo" | "bar">并且我不必通过枚举所有键来重复自己。

有没有办法在创建类型化变量时实现泛型类型参数的推断,而无需创建无操作函数?

标签: typescripttypescript-generics

解决方案


答案是否定的。Type 限制值,表示a:Ta需要是 type 的成员T,如果不是 - 则编译错误。你想说的是a: infer me typeof a,所以反过来。

类型注解是用来限制值的,不是值来限制类型的。TS 允许从值中获取类型,但它不允许获取值的类型并立即对其进行限制。


不过,我们可以制作一些技巧来使其正常工作。考虑类型级解决方案:

type SpecificKeys<T extends string> = {
  [key in T]: string;
};

// type level version of makeSpecificKeys
type MakeSpecificKeys<T extends SpecificKeys<string>> = T;

const foobar = {
  foo: "foo",
  bar: "bar",
};
type FoobarType = MakeSpecificKeys<typeof foobar> // fine 

const badfoobar = {
  foo: 1, // number value dont match SpecificKeys
  bar: "bar",
};
type BadFoobarType = MakeSpecificKeys<typeof badfoobar> // error 

操场

这两个值都由 TS 正确推断,没有任何类型注释foobarbadfoobar下一件事是调用类型级别MakeSpecificKeys,这是您之前创建的一种 id 函数,但这是在类型级别,它以与执行此操作相同的方式限制参数类型makeSpecificKeys。对于badfoobar它显示编译错误。

我在这里展示的无疑是最糟糕的方法,然后是makeSpecificKeys你所做的值构造函数。所以坚持下去。使用上述方法的一点是,它没有任何东西进入运行时,什么时候makeSpecificKeys有。


推荐阅读