Slide 1

Slide 1 text

TypeScriptの次なる大進化なるか!? 条件型を返り値とする関数の型推論 2024-11-16 TSKaigi Kansai 2024

Slide 2

Slide 2 text

発表者紹介 uhyo 株式会社カオナビ フロントエンドエキスパート 普段はTypeScriptとかReactをやっている。 DefinitelyTypedのコントリビューション 回数は3回。 2

Slide 3

Slide 3 text

This Talk このissueの内容を解説します 3

Slide 4

Slide 4 text

トーク概要 このissueは数年前から存在する難題ですが、にわ かにTypeScript 5.7のIteration Planに加えられま した。そのため、TS 5.7の新機能候補として期待 されています。(ただし、TS 5.7にこれが実装さ れることが確約されるものではありません) トーク概要から引用 https://kansai.tskaigi.org/talks/uhyo 4

Slide 5

Slide 5 text

【悲報】TS 5.7で実装されず TSでは、Beta時点で実装されていない機能が 正式版で追加される ことは基本的には ない。 5

Slide 6

Slide 6 text

【朗報】TS 5.8でいけそう https://github.com/microsoft/TypeScript/issues/60287 6

Slide 7

Slide 7 text

解決したい課題 関数の返り値の型に条件型 (conditional type) を使用した場合、asやanyを使わずに型チェックを 通すことができない。 (型推論でconditional typeが発生することがない) 7

Slide 8

Slide 8 text

今回使う例 この例を通して新機能の使い方を解説します function takeFirst( left: number | undefined, right: number | undefined, ): number | undefined { return left ?? right; } (あまり意味のない例ですがもっと意味ある例を簡略化したと思ってください) 8

Slide 9

Slide 9 text

返り値の型を改良する function takeFirst( left: number | undefined, right: number | undefined, ): number | undefined { return left ?? right; } 9 undefinedが返るのはleftもrightも undefinedな場合だけだから、 それを型に反映したい

Slide 10

Slide 10 text

返り値の型を改良する function takeFirst< Left extends number | undefined, Right extends number | undefined > ( left: Left, right: Right, ): Left extends number ? number : Right extends number ? number : number | undefined { return left ?? right as any; } 10

Slide 11

Slide 11 text

返り値の型を改良する function takeFirst< Left extends number | undefined, Right extends number | undefined > ( left: Left, right: Right, ): Left extends number ? number : Right extends number ? number : number | undefined { return left ?? right as any; } 11 LeftかRightがnumberなら 返り値はnumber

Slide 12

Slide 12 text

返り値の型を改良する function takeFirst< Left extends number | undefined, Right extends number | undefined > ( left: Left, right: Right, ): Left extends number ? number : Right extends number ? number : number | undefined { return left ?? right as any; } 12 TSの新機能の力で asの使用を消したい!

Slide 13

Slide 13 text

新機能の制約 今回の新機能がうまく動くためには、返り値の conditional typeが特定の形をしている必要がある。 (unsoundな推論を防ぎ、現実的に推論を可能にするため) T extends A ? AType : T extends B ? BType : never 13

Slide 14

Slide 14 text

新機能の制約 T extends A ? AType : T extends B ? BType : never • ある型引数Tに対して、条件を繰り返し確認する形になっている • Tは特定の引数の型である • AやBはTの制約(constraint)の部分型である • constraint: 型引数定義のT extends FooのFooのこと • どの条件にも当てはまらなった場合はneverにする • Tの型がランタイムの値よりも緩い場合があり条件型のfalse側は情報量がないため 14

Slide 15

Slide 15 text

返り値の型を制約を満たすようにする function takeFirst< Left extends number | undefined, Right extends number | undefined > ( left: Left, right: Right, ): Left extends number ? number : Right extends number ? number : number | undefined { return left ?? right as any; } 15 条件を満たしていない • 複数の型引数が条件に 含まれている • 最後がneverではない

Slide 16

Slide 16 text

返り値の型を制約を満たすようにした function takeFirst< Left extends number | undefined, Right extends number | undefined > ( left: Left, right: Right, ): Right extends number ? number : Right extends number | undefined ? Left : never { return left ?? right as any; } 16 • Rightだけで条件を記述 • 最後をneverにした

Slide 17

Slide 17 text

実装も推論可能な形に直す 誓約は満たしたが、実装も直さないと推論して くれない…… 型がRightの条件分岐なので、実装もRightの条件分岐に する必要がある 17

Slide 18

Slide 18 text

実装も推論可能な形に直した function takeFirst< Left extends number | undefined, Right extends number | undefined > ( left: Left, right: Right, ): Right extends number ? number : Right extends number | undefined ? Left : never { if (right !== undefined) return left ?? right; return left; } 18

Slide 19

Slide 19 text

実装も推論可能な形に直した function takeFirst< Left extends number | undefined, Right extends number | undefined > ( left: Left, right: Right, ): Right extends number ? number : Right extends number | undefined ? Left : never { if (right !== undefined) return left ?? right; return left; } 19 条件型の分岐と同じように rightで分岐することで 型チェックが通った

Slide 20

Slide 20 text

まとめ TS 5.8(予定)では、関数の返り値の条件型を 特定の制約を満たす形にして、 関数の実装も条件型の条件文と一致する 条件分岐で記述することによって、 条件型の型検査をasやany無しで通すことが できる! 20