Optional Variance Annotations for Type Parameters
v4.7から in
/ out
を用いてvarianceを明示できる
例
Getter
型をcovariantとする場合は、型引数に out
を書く
tstype Getter<out T> = () => T;
この T
を引数で使おうとするとerrorになる
tstype Getter<out T> = (a: T) => T; // error
Setter
型をcontravariantにする場合は、型引数に in
を書く
tstype Setter<in T> = (value: T) => void;
State
型をinvariantにする場合は、 in out T
と書く
tstype State<in out T> = {
get: () => T;
set: (value: T) => void;
}
こうすると State
はinvariantになる
雑に言えば、 State<Cat>
と State<Animal>
のような型の間に部分型関係がなくなる
ちなみに逆順で
out in
とは書けない

構造的部分型にvarianceは重要ではないが、導入された理由
ref読み手が理解するのに役立つ
その型のvarianceが即座にわかる
その型の型変数が使われる場所の意図が読める
推論のパフォーマンス向上につながる
TypeScriptは最適化としてvarianceを推論するが、その速度が上がる
推論に失敗することもあるので、その補助になる
書ける状況はかなり制限されているっぽい
関数の定義時には書けないのか

tsfunction add<in T>(arr: Array<T>) {
return [...arr, 'hoge'];
}
これ、関数型にしか使えないのか?
以下のようには書けない?
tstype InvariantArray<in out T> = Array<T> // error
Variance annotations are only supported in type aliases for object, function, constructor, and mapped types
書けないらしい
というか
type
で定義した時は制限があるという感じか

interfaceを使えば書ける
tsinterface InvariantArray<in out T> extends Array<T> {}