tamakipedia

フロントエンドエンジニア。Typescriptもう特訓中です。一日の振り返りや学んだことをちょっとずつ吐いています。

Atomic Design

現在開発中のサービスにおいて
既存のAtomic Design に沿ったコンポーネント設計をしております。

Atomic Design がよくわからなかったのでメモしていきます。

そもそもatomic Design とは

Atomic design is methodology for creating design systems. There are five distinct levels in atomic design: Atomic design はデザインシステムを構築するための手段(方法論)です。大きさのレベルに応じて5つの要素に分類できます。

Atoms, Molecules, Organisms, Templates, Pages それらは Atoms, Molecules, Organisms, Templates, Pages の五つです。

つまり、Atomic DesignはUIを構成するコンポーネントを5つのコンポーネントレベルに分け、
その五つを組み合わせることで全てのUIを表現する手法のことです。

(参照: https://bradfrost.com/blog/post/atomic-web-design/)

単一責任の法則

「モジュールが持つ責務は一つにすべき」という考え方のこと。
Atomic Design でいうところの Atomに一つの責務を置き、それらを組み合わせてアプリケーションを開発する。

分割統治法

「大きな課題を小さく分割することで課題解決をしていく」という考え方。

  

最近コンポーネント設計をしていて、
単一責任の法則も分割統治法も「コンポーネント一つのタスクを最小限にして問題解決、リファクタしやすくする」
ための基本の考え方みたい。
哲学っぽくて面白い。。

参考

https://zenn.dev/offers/articles/20220523-component-design-best-practice

https://qiita.com/MinoDriven/items/76307b1b066467cbfd6a

【typescript】sortを利用して配列を並び替える

sort()メソッドは、配列の要素をソートする関数のこと。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

一般的なuse case

配列にsort() を実行すると昇順に並び替えてくれます。
定義した配列そのものが変更されているので、破壊的変更が加わっていることになります。

const nameList = ["Batto","Atsuki","chieko","Den"];

console.log(nameList.sort())

//["Atsuki", "Batto", "Chieko", "Den"] 

非破壊的ソート

nameList.sort()だと、nameListそのものの配列の順序が変わってしまいます。
それだとイミュータブルの観点からデバックしにくくなってしまいます。

残余構文を利用して、以下のように書き換え

const nameList = ["Batto","Atsuki","chieko","Den"];

const newNameArray = [...nameArray].sort()

//newNameArray → ["Atsuki", "Batto", "Chieko", "Den"] 
//nameArrayはそのまま

ミューテーションについてはこちらの関数型プログラミングお姉さんの動画がおすすめ(笑)
https://www.youtube.com/watch?v=e-5obm1G_FY

比較関数

実はsort()の第一引数に関数を追加することで並び順を制御することができます。

デフォルトの昇順は以下のような比較関数になります。

nameList.sort((a,b) => a + b) //昇順

そして降順は

nameList.sort((a,b) => a - b) //昇順

配列の中身をオブジェクトにし、特定の値でソート

以下のようなオブジェクトでもソートできるということ。。。すごいですよね、、

const stations = [
  {name: "池袋", users: 55223},
  {name: "新宿", users: 10000},
  {name: "渋谷", users: 300},
  {name: "東京", users: 400000},
]

const stationsOriginal = stations.sort((a, b)=> a.users - b.users)


//結果
const stations = [{
  "name": "渋谷",
  "users": 300
}, {
  "name": "新宿",
  "users": 10000
}, {
  "name": "池袋",
  "users": 55223
}, {
  "name": "東京",
  "users": 400000
}] 

//うおおお

【typescript】配列の二列目以降の取り出し

今まではsplice(num)などを利用して
配列を切り分けて取り出していたのですが、最近はもっと直感的な取り出し方があるみたいです。

まとめて取り出し

配列があります

const smalls = [
  "小動物",
  "小型車",
  "小論文"
];

まとめて取り出すことも可能!!

const [a, b , c] = smalls;
//a = '小動物

スプレッド構文を用いて、一番目以降の配列を取得します。

const [, ...other] = smalls;
//["小型車", "小論文"]

新しい配列を作るときは左辺に代入していくのではなく、右辺で配列を直接作って代入する。

const smallsAnime = [
  "コナン君",
  "小次郎"
]
const newArray= [...smalls(slice(0,2),"小売業"],...smallsAnime )]
//[  "小動物", "小型車", "小売業",  "コナン君", "小次郎"]

直感できでわかりやすい、、これから使ってみよう。

【Typescript】Partial<T> ついて

今日はUtility Typesについて学んだので、その学習メモ。
さまざまなユーティリティーがあるが、その一つを例にとってみると少し理解が深まりました。
今回はPartialについて。

Utilty Types とは

Typescriptが提供する型の関数のようなもの。
元のインターフェースを利用し、新しい型を作成することができる。

Partial

それぞれのプロパティをoptionalにしたいときに利用する。

//インターフェースがあります
interface Todo {
    title: string;
    description: string;
}

//インターフェースTodoをもつtodo1
const todo1: Todo = {
    title: "orgnize desk",
    description: "clear clutter",
}

//アップデートするための関数
function updateTodo(todo: Todo, fieldsTodUpdate: Partial<Todo>){
    return {...todo, ...fieldsTodUpdate};
}

//updateTodoを利用し第一引数にコピーしたいオブジェクト、第二引数に追加したいオブジェクトを追加
const todo2 = updateTodo(todo1, {description: "throw out trash",})

この時、updateTodoの第二引数の型を

Partial<Todo>

にすることで、「Todoのプロパティーのうちどれか」を実現することができます。

終わり

こんな感じで、ユーティリティーを使うと元々のインターフェースを加工した型を表現することが可能です。
他にも特定のインターフェースを減らしたり、増やしたり、レコードを作成したり、色々できるみたいなので
現場のコードと照らし合わせつつ勉強していこうと思います。

参考

https://www.typescriptlang.org/docs/handbook/utility-types.html

【TypeScript】Utility Typesをまとめて理解する - Qiita

【Typescript】型ガードについて

型ガード(Type guard)について

if分やcase文を始めたとした条件分岐で変数の方を判別し、ブロック内の変数の型を絞り込む機能のこと。
型を変数内で明示して変換する「キャスト」を使用することを防げる。

type of

変数の型をチェックできます。

type You = string
const you: You = "kotaro";

console.log(typeof You) 
// string

型がstringとnumberの合併型の場合は、stringにしか使えないメソッドを使うとエラーになる

type NumOrStr = number|string ;

function useSomeNumOrStr (arg:NumOrStr): NumOrStr {
  const toUpperCaseStr = arg.toUpperCase()
  return toUpperCaseStr
} 

//Property 'toUpperCase' does not exist on type 'NumOrStr'.
//Property 'toUpperCase' does not exist on type 'number'.

typeof の結果を条件分岐してあげることでエラーを回避できる

type NumOrStr = number|string ;

function useSomeNumOrStr (arg:NumOrStr): NumOrStr {
  if (typeof arg === "string") {
    const toUpperCaseStr = arg.toUpperCase()
    return toUpperCaseStr
  }
  return arg
} 

【Typescript】オブジェクトのキーの文字列のみを許容する動的な型宣言

オブジェクトのキーをオブジェクトの型のプロパティーとしてそのまま流用したい場合。

まず、オブジェクトの型を定義したい場合

type Panda = {
  age: number
}

const panda: Panda = {
 age: 11,
}
//型通り

そのオブジェクトのキーをage, name, color, dream のいずれかにしたい場合

type Panda =  {[K in 'age'|'name'|'color'|'dream']: string}

const panda: Panda = {age: "fifty five" ,name: "Eric Clapton",color: "red", dream: "change the world"}

インターフェースのオブジェクトのキーを次の型のプロパティーにする

type Panda = {
 age: number;
 name: string;
 dream: string;
}

type Pandaaaa = {[K in keyof Panda]: string}
// Panda型のキーがPandaaaaのプロパティーとして使える

上記のように、オブジェクトのキーも特定の文字だけしか入らないようにすることが可能。
特に [K in keyof Object]と記述し、オブジェクトのプロパティを指定したり、
[K in 'A'|'B'|'C']と記述し、特定のキーを直書きすることができる。

【Typescript】extendsを用いてジェネリクスの型パラメータに制約をつける

ジェネリクスで型定義をする際に、特定のプロパティーを持たせるように制限することができる。

引数に存在しないプロパティーがある場合

function showBirthday<T>(person: T): Date {
  
  const birthDay = person.getBirthDay();
  // personの型は未知なのでgetBirthDay()メソッドがあるかどうか未定でエラーになる
  return birthDay;
}

//error : Property 'getBirthDay' does not exist on type 'T'.
//TにgetBirthDayなんてプロパティーは存在しません!!  

extendを利用して型推論時に「引数に特定のプロパティーが存在する」ように制約をつける

type Person = {
    getBirthDay(): Date;
}

function showBirthDay<T extends Person>(person: T): Date {
    const birthDay = person.getBirthDay();
    return birthDay
}

// ok !!

参考:
ジェネリクス — 仕事ですぐに使えるTypeScript ドキュメント