1 분 소요

  • plainToInstance, instanceToPlain에 대해
  • Knex의 insert의 파라미터타입에 대해
  • Record<string,any>에 대해

문제

const insertDataList = plainToInstance(InsertDataDto, dataList);

    return repository.insert(insertDataList);

여기서 repository.insert시 정상작동은 하지만 아래 에러표시가 발생했다.

TS2559: Type InsertDataDto[]  has no properties in common with type  Partial<T>

이걸 어떻게 해결할 수 있을까?
결론만 말하자면 insert의 파라미터타입을 Partial<T>[] 로 변경해주면된다.


1.plainToInstancne, instanceToPlain?

plainToInstancne, instanceToPlain 모두
class-transformer라이브러리에 있는 메소드들이다.

class-transformer는 일반객체를 클래스객체로 전환(혹은 반대로)할 때 유용하게 쓰일 수 있는 라이브러리다.

  • 일반객체 : 리터럴 객체
  • 클래스객체 : 자체정의된 생성자, 속성, 메서드가있는 클래스의 인스턴스

뒤의 예시들은 User클래스가 있다는 가정하게 작성하겠다.

class User {
  id: number;
  name: string;
  age: number;

  constructor(id: number, name: string, age: number) {
    this.id = id;
    this.name = name;
    this.age = age;
  }

  getIntroduceMyself() {
    return `my name is ${this.name} and i'm ${this.age}`;
  }
}

1.1.plainToClass

plainToClass란,
일반자바스크립트 객체를 특정 클래스의 인스턴스로 변환해주는 메소드이다.

먼저 일반객체로 선언한 아래의 경우 출력은?

const obj = {
  id: 1,
  name: 'jayden',
  age: 14,
};

console.log(obj);
console.log(obj instanceof User);

->
alt text
object타입의 일반객체로만 나오게된다.

그러나 일반객체를 클래스의 인스턴스로 변환해주는 아래의 코드를 수행한다면?

const classObj = plainToClass(User, obj);

console.log(classObj);
console.log(classObj instanceof User);
console.log(classObj.getIntroduceMyself());

->
alt text

1.2.classToPlain

classToPlain은,
클래스의 인스턴스인 객체를 다시 자바스크립트 일반객체로 변환해주는 메서드이다.

위에 만들어준 classObj를 다시 아래코드 처리한다면?

const classObjToPlain = classToPlain(classObj);
console.log(classObjToPlain);
console.log(classObjToPlain instanceof User);

->
alt text
결과는 최초 자바스크립트 일반객체였던 결과와 같다.

이 외에 아래의 메서드들이 존재한다.

  • 디폴트값을 설정한 인스턴스를 참조하여 plainToClass를 할 수 있는 plainToClassFromExist(첫 번째 파라미터는 Class가 아닌 디폴트속성이 할당된 인스턴스)
  • 인스턴스를 또 다른 클래스인스턴스로 만들어주는(깊은복사처리) classToClass

    2.원인파악, 왜 Partial<Entity>타입의 파라미터로 전달할 때 오류가 발생했나?

    async insert(data: Partial<T>, ...){...}
    

    우선, 레포지토리의 메서드라 T는 엔티티타입이다.

엔티티타입(T라 칭하겠다)을 PickType하는 InsertDataDto를 단일로 호출했을때,

class insertData = plainToClass(InsertDataDto, data)
repository.insert(insertData)

문제가 되지않지만, 아래의 경우에는 문제가 발생한다.

class insertDataList = plainToClass(InsertDataDto, dataList)
repository.insert(insertDataList)
TS2559: Type InsertDataDto[]  has no properties in common with type  Partial<T> 

InsnertDtoData[]는 T엔티티와 공통속성이 없다는 뜻
InsnertDtoData만 전달했을때는 공통속성이 있다.
그러나 InsnertDtoData[]를 전달했을때는 공통속성이 없다.

3.해결

knex는 일반 자바스크립트객체인 Record<string,any>[] 또는 InsertDataDto[]를 기대하고있다.

따라서 아래의 두 방법이 있다.

3.1. insert의 파라미터타입을 Partial<T> -> Partial<T>[]로 변경

따라서 이 파라미터타입을 받는 batchInsert메서드를 ChunkSize로 지정하여 처리하는것이 좋다.

3.2. insertDataList를 instanceToPlain처리하여 insert로 전달

굳이굳이 Partial<T>타입에 맞춰 넘기려고한다면 dataList를 instanceToPlain처리를 하면된다.
왜냐하면 instanceToPlain은 클래스인스턴스를 자바스크립트 일반객체로 변환하기때문에
Record<string,any>타입이 되므로 전달에 문제가없다.

4.결론

3.1의 해결책인 Partial<T>[] 파라미터타입을 사용하는 batchInsert메서드로 처리를 해주었다.

추가적으로..

Record<string,any>는 무슨용도일까?

Typescript를 사용하다보면 접하는 Record<string,any>.
결론만 말하자면 자바스크립트의 객체를 좀 더 명확히 사용하기 위함이다.
아래처럼, obj1는 value의 타입을 지정할수없지만
obj2는 value타입을 지정할 수 있다.

const obj1 = {
  key1:14,
  key2:"jayden"
}

const obj2:Record<string,number> = {
  key1:14,
  key2:2
}