如何提示 TypeScript 编译器两个泛型值必须相同?

Posted

技术标签:

【中文标题】如何提示 TypeScript 编译器两个泛型值必须相同?【英文标题】:How to hint to TypeScript compiler that two generic values must be the same? 【发布时间】:2019-12-10 10:57:37 【问题描述】:

我有一个简化的函数,它接收一个字符串文字和一个返回 type: [mystringliteral] 的回调。

function myFunc<T>(type: T, callback: () =>  type: T ): ReturnType<typeof callback> 
    return  type ;

除非我在调用时特别设置了T,否则T 被推断为string 而不是文字,并且type 属性上没有类型强制。

// successfully raises compilation error
const x = myFunc<'abc'>('abc', () => ( type: 'def' ));

// does not raise an error
const y = myFunc('abc', () => ( type: 'def' ));

我正在为第三方 npm 包编写声明文件,所以我无法调用任何聪明的函数来提示编译器发生了什么。

我猜我要问的问题对于当前的 TypeScript 规范是完全不可能的(如果我们能做类似&lt;T extends string literal&gt; 这样的事情会很好),但我想我会问。

【问题讨论】:

【参考方案1】:

这里有两个问题。第一个是让编译器推断字符串文字类型。为此,我们需要将string 的约束添加到T。这将向编译器提示我们需要文字类型。

但这还不够。只需将T extends string 添加到签名中,编译器就会推断出'abc' | 'def' 的联合,并且仍然不会产生错误。为了解决这个问题,我们必须让编译器知道T 的第二次出现不应该用于推理。虽然有一个提议 here 为此添加语法,但它尚未实现。但是,我们可以使用 jcalz 建议的解决方法来获得所需的效果:

function myFunc<T extends string>(type: T, callback: () =>  type: NoInfer<T> ): ReturnType<typeof callback> 
    return  type ;

type NoInfer<T> = [T][T extends any ? 0 : never];

// raises an error
const y = myFunc('abc', () => ( type: 'def' ));

【讨论】:

以上是关于如何提示 TypeScript 编译器两个泛型值必须相同?的主要内容,如果未能解决你的问题,请参考以下文章

如何告诉 TypeScript 两个泛型类型是相同的?

如何使用泛型缩小 TypeScript 联合类型

泛型类型的 TypeScript 部分

TypeScript 中泛型的不安全隐式转换

带有泛型的 Typescript 箭头函数的语法是不是发生了变化?

java泛型梳理