Upgrade to Pro — share decks privately, control downloads, hide ads and more …

フロントエンドエンジニアの友人と“型”で話がすれ違った原因 YUMEMI.grow合同LT会i...

フロントエンドエンジニアの友人と“型”で話がすれ違った原因 YUMEMI.grow合同LT会in横浜 @Kaito-Dogi

2023/05/18 開催の YUMEMI.grow 合同 LT 会 in 横浜 にて登壇しました。

-----

フロントエンドエンジニアの友人と開発したとき"型"という言葉の解釈で話が噛み合っていないことに気付きました。
そのすれ違いの原因は型システムの違いにありました。
同じ静的型付け言語で"型"という概念は共通してありますが、友人が扱っている TypeScript の型システムを"構造的部分型"、私が扱っている Kotlin の型システムを"公称型"といいます。
今回の LT では UI の実装例を題材としながら、それらの型システムの違いを学んでいきます。

Kaito-Dogi

May 18, 2023
Tweet

More Decks by Kaito-Dogi

Other Decks in Programming

Transcript

  1. ❏ 置換できない
 ❏ 名前で区別される
 ❏ 厳密さ・安全性
 ❏ 同じ構造で置換できる
 ❏ 構造で区別される


    ❏ 柔軟性・拡張性
 公称型
 構造的部分型
 (Kotlin など)
 (TypeScript など)

  2. ❏ 置換できない
 ❏ 名前で区別される
 ❏ 厳密さ・安全性
 ❏ 同じ構造で置換できる
 ❏ 構造で区別される


    ❏ 柔軟性・拡張性
 公称型
 構造的部分型
 (Kotlin など)
 (TypeScript など)

  3. 公称型(Kotlin)の場合
 class Dog( val name: String, ) { fun move()

    { // わんわんは動く } } class Cat( val name: String, ) { fun move() { // にゃんにゃんも動く } } 構造は同じ
 名前は異なる

  4. 構造的部分型(TypeScript)の場合
 class Dog { name: string; constructor(name: string) { this.name

    = name; } move() { // わんわんは動く } } class Cat { name: string; constructor(name: string) { this.name = name; } move() { // にゃんにゃんも動く } } 名前は異なる
 構造は同じ

  5. 構造的部分型(TypeScript)の場合
 const dog: Dog = new Cat("tama"); console.log(dog.name); // =>

    "tama" 左辺の変数と右辺のインスタンスの型が異なるが代入可能
  

  6. 構造的部分型(TypeScript)の場合
 const dog: Dog = new Cat("tama"); console.log(dog.name); // =>

    "tama" 左辺の変数と右辺のインスタンスの型が異なるが代入可能
  👆 構造で型を区別するため 

  7. LazyColumn
 import androidx.compose.foundation.lazy.items @Composable fun MessageList(messages: List<Message>) { LazyColumn {

    items(messages) { message -> MessageRow(message) } } } 出典:https://developer.android.com/jetpack/compose/lists 
 items に渡せる型は1種類だが
 3種類のリストアイテムを渡したい

  8. sealed class
 sealed class HomeScreenUiModel { // 横長のリストアイテム data class

    ListItemUiModel( val text: String, ) : HomeScreenUiModel() // 大きい正方形のリストアイテム data class LargeListItemUiModel ... // 複数カラムのリストアイテム data class MultiColumnListItemUiModel ... } 継承することで
 HomeScreenUiModel として 扱える
 継承できる class を限定

  9. @Composable fun HomeScreen(uiModels: List<HomeScreenUiModel>) { LazyColumn { items(uiModels) { uiModel

    -> when (uiModel) { is HomeScreenUiModel.ListItemUiModel -> ListItem(text = uiModel.text) is HomeScreenUiModel.LargeListItemUiModel -> LargeListItem(text = uiModel.text) is HomeScreenUiModel.MultiColumnListItemUiModel -> MultiColumnListItem(texts = uiModel.texts) } } } } 型の名前で条件分岐
 HomeScreenUiModel の
 リストとして渡す

  10. FlatList
 const App = () => { return ( <SafeAreaView

    style={styles.container}> <FlatList data={DATA} renderItem={({ item }) => <Item title={item.title} />} keyExtractor={(item) => item.id} /> </SafeAreaView> ); }; 出典:https://reactnative.dev/docs/flatlist 
 data に渡せる型は1種類だが
 3種類のリストアイテムを渡したい

  11. ユニオン型
 // 横長のリストアイテム type ListItemUiModel = { type: "item"; text:

    string; }; // 大きい正方形のリストアイテム type LargeListItemUiModel = ... // 複数カラムのリストアイテム type MultiColumnListItemUiModel = ... type HomeScreenUiModel = | ListItemUiModel | LargeListItemUiModel | MultiColumnListItemUiModel; 連結した型のうち
 「どれか」を表す
 構造を表す文字列を
 持たせておく

  12. const HomeScreen: React.FC<Props> = ({ uiModels }) => ( <FlatList<HomeScreenUiModel>

    data={uiModels} renderItem={(item) => <HomeScreenUiModelBinder item={item.item} />} /> ); const HomeScreenUiModelBinder: React.FC<Props> = ({ item }) => { switch (item.type) { case "item": return <ListItem text={item.text} />; case "large": return <LargeListItem text={item.text} />; case "multi-column": return <MultiColumnListItem texts={item.texts} />; } }; 型の構造で
 条件分岐
 HomeScreenUiModel の
 リストとして渡す

  13. まとめ
 ❏ 同じ静的型付け言語でも異なる型システムがある
 ❏ 公称型:置換できない
 ❏ 構造的部分型:同じ構造で置換できる
 ❏ “型”定義とは
 ❏

    Android エンジニアの私:型の名前を定義すること
 ❏ フロントエンドエンジニアの友人:型の構造を定義すること

  14. 参考記事
 ❏ 構造的部分型(structural subtyping)| TypeScript 入門『サバイバル TypeScript』 https://typescriptbook.jp/reference/values-types-variables/structural-subtyping 
 ❏

    Lists and grids | Compose | Android Developers 
 https://developer.android.com/jetpack/compose/lists 
 ❏ Sealed classes and interfaces | Kotlin Documentation 
 https://kotlinlang.org/docs/sealed-classes.html 
 ❏ FlatList · React Native 
 https://reactnative.dev/docs/flatlist 
 ❏ TypeScript: Handbook - Unions and Intersection 
 https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html 
 ❏ ユニオン型(union type)| TypeScript入門『サバイバル TypeScript』 
 https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html 
 ❏ Keishin Yokomaku,(2023), Kotlin で Either したい 
 https://speakerdeck.com/keithyokoma/either-in-kotlin