TypeScript 구조적 타입 시스템과 초과 프로퍼티 체크 이해하기

max·2023년 8월 12일
1
post-thumbnail

구조적 타입 시스템은 TypeScript의 핵심 특징 중 하나입니다. 그러나 때로는 이 시스템이 초과 프로퍼티 체크와 어떻게 관련되어 있는지 이해하는 것이 어려울 수 있습니다. 본 글에서는 이러한 초과 프로퍼티 체크의 동작 방식과 TypeScript의 설계 의도를 설명하고자 합니다.

구조적 타입 시스템의 정의

TypeScript의 구조적 타입 시스템은 객체의 "형태"나 "구조"에 기반하여 타입의 호환성을 판단하는 방식입니다. 즉, 타입의 이름이나 선언 방식이 아닌, 객체의 실제 구조와 그 구조 안에 있는 프로퍼티들을 기반으로 타입 검사를 진행합니다. 이런 방식의 타입 체계는 Go(Golang)에서도 확인 할 수 있습니다.

구조적 타입 시스템의 핵심은 유연성 입니다. 객체가 특정 타입의 요구사항을 충족시키면 해당 타입으로 간주됩니다 즉, 어떤 추가 프로퍼티가 있더라도 문제가 되지 않습니다. 하지만, 이러한 유연성은 때로는 예상치 못한 오류를 초래할 수 있습니다. 이를 방지하기 위해 초과 프로퍼티를 체크하게 됩니다.

초과 프로퍼티 체크

초과 프로퍼티 체크는 객체 리터럴을 특정 타입으로 지정하려 할 때, 해당 타입에 정의되지 않은 프로퍼티가 객체 리터럴에 존재하는 경우 에러를 발생시키는 체크 메커니즘입니다.

자세한 동작을 살펴보겠습니다.

구조적 타입 시스템과 초과 프로퍼티 체크의 동작

1. 변수에 다른 변수 객체를 할당할 때

interface A {
  a: number;
  b: number;
}

const b = {
  a: 1,
  b: 2,
  c: 3,
}

const a: A = b; // no error

const aa: A = {
  a: 1,
  b: 2,
  c: 3, // type error!
};

이미 선언된 변수 b 를 다른 변수에 할당하는 경우, 초과 프로퍼티 c 에 대한 에러는 발생하지 않습니다. 그러나 객체 리터럴을 직접 할당할 때는 '초과 프로퍼티 체크'가 동작하며 에러가 발생합니다.

2. 함수 시그니쳐 타입의 Return에 객체를 사용할 때

interface A {
  a: number;
  b: number;
}

type Func = () => A;

const a: Func = () => ({
  a: 1,
  b: 2,
  c: 3, // no error
});

const aa = (): A => ({
  a: 1,
  b: 2,
  c: 3, // type error!
});

함수 반환 타입을 함수 시그니처(type Func = () => A) 로 지정하면, '초과 프로퍼티 체크'가 발생하지 않습니다. 반면, 직접 반환 타입을 지정할 경우(const aa = (): A) '초과 프로퍼티 체크'가 동작하며 에러가 발생합니다.

3. 함수 시그니처 타입의 파라미터로 객체 전달할 때

interface A {
  a: number;
  b: number;
}

type Func = (params: A) => void;

const func: Func = ({ a, b }) => {};

const a = {
  a: 1,
  b: 2,
  c: 3,
};

func(a); // no error

func({
  a: 1,
  b: 2,
  c: 3, // type error!
});

함수의 매개변수로 이미 할당된 객체를 전달할 경우(func(a)) '초과 프로퍼티 체크'가 발생하지 않아 에러가 발생하지 않습니다. 그러나 객체 리터럴을 직접 전달할 때(func({ … }))는 '초과 프로퍼티 체크'가 동작하며 에러가 발생합니다.

결론

TypeScript의 구조적 타입 시스템은 객체의 실제 형태가 해당 타입으로 지정된 형태를 충족하는지만 확인합니다. 때문에 객체가 추가적인 프로퍼티를 가지고 있더라도, 해당 타입의 요구사항을 만족한다면 타입 검사를 통과하게 됩니다. 이는 코드의 유연성을 제공하며 초과 프로퍼티 체크는 이 유연성 내에서의 실수를 방지하기 위한 안전장치로 작동합니다. 객체 리터럴로 직접 타입을 지정하려고 할 때나 반환값으로 직접 타입을 지정한 경우는 초과 프로퍼티 체크가 적용되어 에러를 발생시킵니다. 이러한 특징은 코드의 안정성을 높이는 데 도움을 주면서, 동시에 유연성을 제공하려는 TypeScript의 설계 의도를 반영한 것입니다.

profile
Frontend Engineer

2개의 댓글

comment-user-thumbnail
2023년 8월 12일

개발자로서 배울 점이 많은 글이었습니다. 감사합니다.

1개의 답글