TypeScript:测试条件类型相等 - 理解语法

TypeScript: testing conditional type equality - understanding the syntax

我一直在尝试比较 TypeScript 中类型的相等性。我偶然发现了这种方法:

type SomeType = {
  property: string;
}

type OtherType = {
  property: string;
}

/**
 * The two types passed are evaluated for equivalence; returning true if they
 * are equivalent types and false if not
 * 
 * Based upon Matt McCutchen's comment:
 * https://github.com/microsoft/TypeScript/issues/27024#issuecomment-421529650
 */
type Equals<Type1, Type2> =
    (<Type1Match>() => Type1Match extends Type1 ? "match!" : "not a match") extends
    <Type2Match>() => Type2Match extends Type2 ? "match!" : "not a match"
    ? true
    : false;

type IsTrue<T extends true> = T

/**
 * This expression will evaluate that our types match; note
 * the underscore at the start which indicates this is expected
 * to be an unused type 
 */
type test = IsTrue<Equals<SomeType, OtherType>

我正在阅读和重新阅读上面的 Equals,我对 (<Type1Match>() => Type1Match extends Type1 ? "match!" : "not a match") 开头的 <Type1Match>() => 感到有些困惑。

这里似乎没有混合功能;还是那里,我错过了什么?这只是引入新泛型的后门方式吗?

根据 Titians 的精彩回答更新

Titian 的更新(和更清晰)方法的不幸之处在于它不能很好地处理所有类型等价性检查。考虑提香 Equals2 未能发现差异的 any 比较。我放在一起的另一个简化的Equals3也是如此。

但是 Equals 确实成功检测到了这些问题。我心中的问题是“为什么这行得通?”还有“我可以依靠这个前进吗?”。所以,如果我有依赖于能够执行此相等性检查的代码,那么我是否在此处建立在流沙之上?这种方法是否依赖于将来可能会改变的编译器实现细节?

See in playground

type SomeType = {
  property: any;
}

type OtherType = {
  property: string;
}

/**
 * The two types passed are evaluated for equivalence; returning true if they
 * are equivalent types and false if not
 * 
 * Based upon Matt McCutchen's comment:
 * https://github.com/microsoft/TypeScript/issues/27024#issuecomment-421529650
 */
type Equals<Type1, Type2> =
    (<Type1Match>() => Type1Match extends Type1 ? "match!" : "not a match") extends
    <Type2Match>() => Type2Match extends Type2 ? "match!" : "not a match"
    ? true
    : false;


type Equals2<Type1, Type2> =
    (<Type1Match extends Type1>() => Type1Match) extends (<Type2Match extends Type2>() => Type2Match)
    ? true
    : false;

type Equals3<Type1, Type2> =
    [Type1] extends [Type2] ? (
        [Type2] extends [Type1] ? true : false
    ) : false;

type IsTrue<T extends true> = T

/**
 * This expression will evaluate that our types match; note
 * the underscore at the start which indicates this is expected
 * to be an unused type 
 */
type test = IsTrue<Equals<SomeType, OtherType>> // errors as the types are not equivalent
type test2 = IsTrue<Equals2<SomeType, OtherType>> // unfortunately does not error
type test3 = IsTrue<Equals3<SomeType, OtherType>> // unfortunately does not error

<Type1Match>() => Type1Match extends Type1 ? "match!" : "not a match" 实际上是函数签名,Type1Match 是函数签名的类型参数。从 return 类型中删除条件类型使其更加清晰 <Type1Match>() => SomeReturnType。 return 类型是条件类型 Type1Match extends Type1 ? "match!" : "not a match"(这确实使它确实很难阅读)。

所有这一切的原因是TS在非常有限的地方使用了等价比较。这是其中之一,在涉及类型参数的条件类型中。