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

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

フロントエンドエンジニアの友人と“型”で話がすれ違った原因 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. フロントエンドエンジニアの友人と

    “型”で話がすれ違った原因

    YUMEMI.grow 合同 LT 会 in 横浜

    @Kaito-Dogi


    View full-size slide

  2. 自己紹介

    ❏ どぎー

    ❏ 株式会社ゆめみ

    ❏ Android エンジニア

    ❏ React Native に挑戦中🔥

    @Kaito_Dogi

    @Kaito-Dogi


    View full-size slide

  3. フロントエンドエンジニアの友人と

    開発したとき💭


    View full-size slide

  4. 普段 Kotlin を扱っている私が

    TypeScript を学んでみた


    View full-size slide

  5. 「“型”の解釈違くない?😥」


    View full-size slide

  6. どちらも静的型付け言語


    View full-size slide

  7. “型”の概念は共通しているはず…?


    View full-size slide

  8. 型システムが異なっていた💡


    View full-size slide

  9. Kotlin 👉 公称型

    TypeScript 👉 構造的部分型


    View full-size slide

  10. 今回の目的

    公称型と構造的部分型の

    違いを学ぶ


    View full-size slide

  11. ❏ 置換できない

    ❏ 名前で区別される

    ❏ 厳密さ・安全性

    ❏ 同じ構造で置換できる

    ❏ 構造で区別される

    ❏ 柔軟性・拡張性

    公称型
 構造的部分型

    (Kotlin など)
 (TypeScript など)


    View full-size slide

  12. ❏ 置換できない

    ❏ 名前で区別される

    ❏ 厳密さ・安全性

    ❏ 同じ構造で置換できる

    ❏ 構造で区別される

    ❏ 柔軟性・拡張性

    公称型
 構造的部分型

    (Kotlin など)
 (TypeScript など)


    View full-size slide

  13. 公称型(Kotlin)の場合

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

    名前は異なる


    View full-size slide

  14. 公称型(Kotlin)の場合

    左辺の変数と右辺のインスタンスの型が異なるのでエラー

     

    val tama: Dog = Cat("tama")
    // => Type mismatch: inferred type is
    // Cat but Dog was expected

    View full-size slide

  15. 公称型(Kotlin)の場合

    左辺の変数と右辺のインスタンスの型が異なるのでエラー

    👆 名前で型を区別するため 

    val tama: Dog = Cat("tama")
    // => Type mismatch: inferred type is
    // Cat but Dog was expected

    View full-size slide

  16. 構造的部分型(TypeScript)の場合

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

    構造は同じ


    View full-size slide

  17. 構造的部分型(TypeScript)の場合

    const dog: Dog = new Cat("tama");
    console.log(dog.name);
    // => "tama"
    左辺の変数と右辺のインスタンスの型が異なるが代入可能

     


    View full-size slide

  18. 構造的部分型(TypeScript)の場合

    const dog: Dog = new Cat("tama");
    console.log(dog.name);
    // => "tama"
    左辺の変数と右辺のインスタンスの型が異なるが代入可能

     👆 構造で型を区別するため 


    View full-size slide

  19. UI を実装しながら理解していこう


    View full-size slide

  20. 今回実装する UI

    ❏ 3種類のアイテムをリスト表示

    ❏ ListItem(横長)

    ❏ LargeListItem(大きい正方形)

    ❏ MultiColumnListItem(複数カラム)

    ❏ 各アイテムの個数制限なし

    ❏ アイテムの順番は好きに入れ替え可


    View full-size slide

  21. Jetpack Compose(Kotlin)

    での実装


    View full-size slide

  22. LazyColumn

    import androidx.compose.foundation.lazy.items
    @Composable
    fun MessageList(messages: List) {
    LazyColumn {
    items(messages) { message ->
    MessageRow(message)
    }
    }
    }
    出典:https://developer.android.com/jetpack/compose/lists 

    items に渡せる型は1種類だが

    3種類のリストアイテムを渡したい


    View full-size slide

  23. sealed class

    sealed class HomeScreenUiModel {
    // 横長のリストアイテム
    data class ListItemUiModel(
    val text: String,
    ) : HomeScreenUiModel()
    // 大きい正方形のリストアイテム
    data class LargeListItemUiModel ...
    // 複数カラムのリストアイテム
    data class MultiColumnListItemUiModel ...
    }
    継承することで

    HomeScreenUiModel として
    扱える

    継承できる class を限定


    View full-size slide

  24. @Composable
    fun HomeScreen(uiModels: List) {
    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 の

    リストとして渡す


    View full-size slide

  25. React Native(TypeScript)

    での実装


    View full-size slide

  26. FlatList

    const App = () => {
    return (

    data={DATA}
    renderItem={({ item }) => }
    keyExtractor={(item) => item.id}
    />

    );
    };
    出典:https://reactnative.dev/docs/flatlist 

    data に渡せる型は1種類だが

    3種類のリストアイテムを渡したい


    View full-size slide

  27. ユニオン型

    // 横長のリストアイテム
    type ListItemUiModel = {
    type: "item";
    text: string;
    };
    // 大きい正方形のリストアイテム
    type LargeListItemUiModel = ...
    // 複数カラムのリストアイテム
    type MultiColumnListItemUiModel = ...
    type HomeScreenUiModel =
    | ListItemUiModel
    | LargeListItemUiModel
    | MultiColumnListItemUiModel;
    連結した型のうち

    「どれか」を表す

    構造を表す文字列を

    持たせておく


    View full-size slide

  28. const HomeScreen: React.FC = ({ uiModels }) => (

    data={uiModels}
    renderItem={(item) => }
    /> );
    const HomeScreenUiModelBinder: React.FC = ({ item }) => {
    switch (item.type) {
    case "item":
    return ;
    case "large":
    return ;
    case "multi-column":
    return ;
    } };
    型の構造で

    条件分岐

    HomeScreenUiModel の

    リストとして渡す


    View full-size slide

  29. まとめ

    ❏ 同じ静的型付け言語でも異なる型システムがある

    ❏ 公称型:置換できない

    ❏ 構造的部分型:同じ構造で置換できる

    ❏ “型”定義とは

    ❏ Android エンジニアの私:型の名前を定義すること

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


    View full-size slide

  30. サンプルリポジトリはこちら👇

    https://github.com/Kaito-Dogi/type-systems


    View full-size slide

  31. 参考記事

    ❏ 構造的部分型(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

    View full-size slide

  32. ありがとうございました🙌


    View full-size slide