これは面白い課題ですね。
結論から言ってしまうと、ジェネリクスのA
は解決しておらず、条件付き型(extends
)同士が割り当て可能になるには、「extends
直後の型が同値でなければならない」という性質を利用しているようです。
詳細に説明するために、一旦下記のように分解してみます。下記x
がy
に代入可能なら、Equals
は1を返すということになります。
declare let x: <A>() => A extends A2 ? 1 : 0
declare let y: <B>() => B extends A1 ? 1 : 0
x = y
クレジットにあるIssueのコメントで次のように理由が述べられていました:
Here's a solution that makes creative use of the assignability rule for conditional types, which requires that the types after extends be "identical" as that is defined by the checker:
つまり、上記のコードで言えば、x
のextends
の直後の型A2
と、y
のextends
の直後の型A1
が同一の場合のみ、x
がy
に代入可能になるようにしているようです。
具体的に、A1
がany
、A2
がstring
であるケースを考えてみます:
playground
declare let x: <A>() => A extends string ? 1 : 0
declare let y: <B>() => B extends any ? 1 : 0
// エラー: 代入できない
// Type '<B>() => B extends any ? 1 : 0' is not assignable to type '<A>() => A extends string ? 1 : 0'.
// Type 'A extends any ? 1 : 0' is not assignable to type 'A extends string ? 1 : 0'.
// Type '0 | 1' is not assignable to type 'A extends string ? 1 : 0'.
// Type '0' is not assignable to type 'A extends string ? 1 : 0'.(2322)
x = y
A1
とA2
がともにstring
であるケースでは:
playground
declare let x: <A>() => A extends string ? 1 : 0
declare let y: <B>() => B extends string ? 1 : 0
// 代入可能
x = y
ではなぜ条件付き型(extends
)同士が割り当て可能になるには、「extends
直後の型が同値でなければならない」という性質があるのでしょうか。
extends
直後の型が同値でなくても、条件付き型同士が割り当て可能だと仮定してみます:
declare let x: <A>() => A extends string ? 1 : 0
declare let y: <B>() => B extends number ? 1 : 0
// 1
const x_1 = x<string>()
// 0
const y_1 = y<string>()
x = y
// xの関数シグネチャの定義によれば、x_2は`1`のはず
// しかし、xにyを代入できており、y_1から`0`なので
// 戻り値は `1 | 0` のユニオン型でなければ矛盾する
const x_2 = x<string>()
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/11/24 01:53 編集