【问题标题】:Return generic type of type alias返回类型别名的泛型类型
【发布时间】:2021-07-31 20:22:05
【问题描述】:

我有一个带有两个泛型参数的类型

type FirstLevelType<A, Z> = {
  _: "typeCheck";
};

但我需要用另一个包装这个类型

type TestWrapperType<T, U> = FirstLevelType<T, U>;

使用 TestWrapperType 创建变量后,我需要获取泛型参数。

const a: TestWrapperType<{ cat: string }, { dog: number }> = {
  _: "typeCheck",
};

但我只能使用 FirstLevelType 来防止代码长度增加,因为可以多次创建包装类型。

type ExtendFirst = typeof a extends FirstLevelType<infer T, infer U>
  ? T
  : "not extended";

结果类型 = 未知

例外类型 = {cat: string}

type ExtendWrapper = typeof a extends TestWrapperType<infer T, infer U>
  ? T
  : "not extended";

结果类型 = {cat: string}

例外类型 = {cat: string}

为什么 ExtendFirst 类型未知?我该如何解决这个问题。

[更新 1]

如果 FirstLevelType 声明为接口,则 Resulted Type 将是正确的。但是,当我的包装器具有其他属性时,再次导致类型未知。

type TestWrapperType<T, U> = FirstLevelType<T, U> & {
  seal?: boolean;
};

【问题讨论】:

  • 您指的还有哪些其他属性?请提供其他属性的示例
  • FirstLevelType&lt;A,Z&gt;AZ 没有结构依赖是否有原因?这样做很麻烦,因为FirstLevelType&lt;string, number&gt; 等价于FirstLevelType&lt;boolean, Date&gt;,因此类型参数的推断是个问题。我看到您已经接受了有关更改为界面的答案,但我希望这很脆弱。如果你想要更健壮的类型推断,最好将AZ 类型的成员添加到FirstLevelType&lt;A,Z&gt;
  • @jcalz 使用这些泛型是因为它们与继承的FirstLevelType 对象没有直接关系,但有用于动态创建类方法,其中A 是参数,Z 是返回,对象的相关键Record&lt;string, FirstLevelType&lt;A,Z&gt;&gt;是方法名。
  • 但是你没有使用参数;见this FAQ entry
  • 这与其说是“规则”,不如说是防止推理异常的保险。也许没有它你的代码可以正常工作,但也许有一天你的使用或编译器实现会发生一些变化,导致结构检查,然后问题会再次出现。如果它对你有用,你不一定要改变它,但你至少应该意识到这个问题。

标签: javascript typescript


【解决方案1】:

如果你想让它工作,只需使用interface 代替FirstLevelType 而不是type

// used interface instead of type
interface FirstLevelType<A, Z> {
    _: "typeCheck";
};

type TestWrapperType<T, U> = FirstLevelType<T, U>;


const a: TestWrapperType<{ cat: string }, { dog: number }> = {
  _: "typeCheck",
};

type ExtendFirst = typeof a extends FirstLevelType<infer T, infer _>
    ? T
    : "not extended";


type ExtendWrapper = typeof a extends TestWrapperType<infer T, infer _>
    ? T
    : "not extended";

Playground

我相信这是因为当 types 急切地评估接口时,接口是惰性的。

如果 FirstLevelType 声明为接口,则 Resulted Type 何时正确。但是,当我的包装器具有其他属性时,再次导致类型未知。

由于您的TestWrapperType 可能会扩展,您应该推断出这些rest 道具:

type FirstLevelType<A, Z> = {
    _: "typeCheck";
};


type TestWrapperType<T, U> = FirstLevelType<T, U> & {
    seal?: boolean;
}

const a: TestWrapperType<{ cat: string }, { dog: number }> = {
    _: "typeCheck",
};

// { cat: string; }
type ExtendFirst = typeof a extends FirstLevelType<infer T, infer _> & infer RestProps
    ? T
    : "not extended";

现在您可以将type 用于FirstLevelType

【讨论】:

  • 这是正确答案,但不能解决我的问题:(因为我的包装器有自己的属性。
  • 什么意思?你能举个例子吗?
  • 我已经更新了我的问题,请看看那里。
  • 如果FirstLevelType&lt;A,Z&gt; 在结构上不依赖于它的类型参数,那么就不能保证类型参数的推断会正常工作。我认为懒惰地评估接口意味着编译器假设结构依赖,但我不知道它是否可以依赖。为获得最佳结果,应该有 AZ 类型或依赖于它们的类型的成员。
  • @jcalz 感谢您的评论。如果使用泛型,它工作得很好。不知道类型和接口之间的这种差异
猜你喜欢
  • 1970-01-01
  • 2021-12-25
  • 1970-01-01
  • 1970-01-01
  • 2016-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多