[TIL]Typescript Callsigniture만들기

ohoho·2024년 10월 16일

슬기로운스터디

목록 보기
30/54

오늘 공부한것 & 기억할 내용

🚨codeChallenge에서 요구한건 여러개의 callsigniture만들기였다.
하지만 지문을 잘못이해하고 여러개 이부분에 꽂혀서 한번에 만들어주지~! 하면서 미래를 보지 못한채 class로 만들어버리는 이슈 발생

class

class Default<T>{
  	//전달받을 프로퍼티 item T[]선언
  	//class의 프로퍼티를 사용할일이 없다면 지워도됨(이 코드에선 지워도됨)
    protected item:T[]
  	//constructor또한 사용 안하면 지워도됨
    constructor(){
      	//[] 초기화 시켜주기
        this.item = []
    }
  	//배열의 마지막 값을 받을 함수
    last(item:T[]):T{
        return item[item.length - 1]
    }
  	//두번째 인자를 배열의 첫번째에 넣는 함수
    prepend(item:T[],item2:T):T[]{
        return [item2,...item]
    }
  	//배열을 합쳐서 새로운 배열을 리턴하는 함수
    mix(item:T[],item2:T[]):T[]{
        return [...item,...item2]
    }
  	//배열의 길이
    count(item:T[]):number{
        return item.length
    }
  	//배열에서 두번째 인자의(item2) index값 리턴 값이 없다면 null리턴
    findIndex(item:T[],item2:T):number | null{
       return item.indexOf(item2) !== -1 ? item.indexOf(item2) : null
    }
  	//배열 자르기 item3은 옵션
    slice(item:T[],item2:number,item3?:number):T[]{
        return item.slice(item2,item3)
    }
}

const arr = new Default<number | string>()
const lastItem = arr.last([1, 2, 3, 4, "bye"])
const prependItem = arr.prepend([1,2,3,4,5],"hola")
const mixItem = arr.mix([1,2],["hi"])
const countItem = arr.count([1,2,3,4,5,6,7])
const findIndexItem = arr.findIndex([1,2,3,4,5,6],3)
const sliceItem = arr.slice([1,2,3,4,5,6,7],3)

class로 만들면서 class Default<T>여기서 <T>라고 제네릭을 선언해줬는데 왜 아래에서 인스턴스를 새성할때 new Default<number | string>()이렇게 써줘야하는지 이해가 안갔다.
코드를 하면서 문서도 찾아보면서 알아낸 바로는 인스턴스를 생성할때 구체적인 타입을 명시함으로서 타입의 안정성이 높아진다.
그리고 클래스에 바로 쓰지 않고 인스턴스에서 쓰면 클래스의 재사용성이 높아진다.


callsigniture

  • 함수의 타입을 정의
//callsigniture를 만들기 위해 type 지정해 Initial<T> generic을 넣어준다.
type Initial<T> = {
  	//여기 안에서 함수의 타입들을 지정해준다.
  	//class를 사용해서 만들었을때 함수 괄호 안에 넣어줬던것들
    last:(item:T[]) => T
    prepend:(item:T[],item2:T) => T[]
    mix:(item:T[],item2:T[]) => T[]
    count:(item:T[]) => number
    findIndex:(item:T[],item2: T) => number | null
    slice:(item:T[],item2:number,item3?:number) => T[]
}


//기능을 구현하기 위해 객체 변수 생성
const Default: Initial<number | string> = {
  	//기능 구현 이름은 Initial안에 들어 있는 메소드 이름과 동일해야함
    last:(item) => item[item.length - 1],
    prepend:(item,item2) => [item2,...item],
    mix:(item,item2) => [...item,...item2],
    count:(item) => item.length,
    findIndex:(item,item2) => item.indexOf(item2) !== -1 ? item.indexOf(item2) : null,
    slice:(item,item2,item3) => item.slice(item2,item3),
}

//메소드 호출을 위해 Default 참조
const lastItem = Default.last([1,2,3,4,"bye"])
const prependItem = Default.prepend([1,2,3,4,5],"hola")
const mixItem = Default.mix([1,2],["hi"])
const countItem = Default.count([1,2,3,4,5,6,7])
const findIndexItem = Default.findIndex([1,2,3,4,5,6],3)
const sliceItem = Default.slice([1,2,3,4,5,6,7],3)

class로 만들었던것들을 callsigniture로 쓰기위해 type을 만들어 함수의 타입을 각각 지정해주고 기능을 구현하기 위해 Default라는 객체를 만들어 각각의 기능을 넣어주고 마지막에 Default을 참조해 메소드를 호출시켰다.

배운점 & 느낀점

class로 만든걸볼때 type으로 callsigniture를 만드는것보다 쉽다고 생각했다.
class 내부에 함수를 만들어 한번에 타입지정과, 구현할 코드를 만들 수 있기때문이다.
그래도 callsigniture를 쓰면 가독성이 좋고 코드가 간결해 보인다.
이래저래 의도치 않게 두번의 코드를 작성했는데 쓰는 코드는 동일한데 어떻게 배치하느냐의 차이같다.

	//class
  last(item:T[]):T{
        return item[item.length - 1]
    }

	//callsigniture
  type Initial<T> = {
    last:(item:T[]) => T
  }
  const Default: Initial<number | string> = {
    last:(item) => item[item.length - 1],
  }

0개의 댓글