타입스크립트 인터페이스를 임의의 객체에 할당하지 못하는 문제

박기완·2021년 12월 7일
3

문제

인터페이스로 정의한 객체를 임의의 객체(Record<string, unknown>)에 할당할 수 없었다. string 타입의 index signature가 인터페이스엔 없다는 오류가 발생했다.

interface FooInterface {
  foo: string
}

declare function returnFoo(): FooInterface
declare function acceptObject(obj: Record<string, unknown>): void

acceptObject(returnFoo())
// Argument of type 'FooInterface' is not assignable to parameter of type 'Record<string, unknown>'.

이를 간소화하면,

interface FooInterface {
  foo: string
}

const bar: Record<string, unknown> = { foo: '' } as FooInterface
// Type 'FooInterface' is not assignable to type 'Record<string, unknown>'.
// Index signature for type 'string' is missing in type 'FooInterface'.(2322)

해결책

인터페이스에 index signature를 정의하거나 type으로 객체를 정의하면 된다.

interface FooInterface {
  [key: string]: string | undefined // 명시적 속성의 모든 타입을 가지고 있어야 함
  foo: string
}

const bar: Record<string, unknown> = { foo: '' } as FooInterface // OK

하지만 이렇게 하면 FooInterface로 정의한 객체는 아무 속성이나 접근이 가능해진다.

type FooType = {
  foo: string
}

const bar: Record<string, unknown> = { foo: '' } as FooType // OK

정리

엄격한 타입스크립트 세계에서 생각하면 Record<string, unknown>를 쓰는 일 따위는 하지 말아야 한다. 모든 파라미터와 리턴 값은 명확한 타입으로 정의해서 안전한 타입 시스템을 구축해야한다.

하지만 현실 세계에선 어떤 값이 있는지 모르는 객체를 다룰 일이 많다. 해당 객체를 타이핑할 수 없다면 인터페이스에 인덱스 시그니처를 명시하는 건 어떨까? 리팩토링하고 싶은 욕구가 드는 흔적을 남길 수 있다. 나중에 코드를 보게 될 미래의 내가 리팩토링 하겠지.

TS Playground

0개의 댓글