TS 4.9 satisfies, 그로 인한 영향

dante Yoon·2022년 12월 4일
3

js/ts

목록 보기
6/14

동영상으로 보기

안녕하세요, 단테입니다.
타입스크립트 4.9의 변경점에 대해 이야기 해보려고 합니다.

TS 4.9 버전은 아래와 같은 업데이트 히스토리를 가지고 있습니다.

4.9 버전에서 추가되는 statisfies operator는 기존 리턴 타입을 제

대로 추론하지 못한 타입 스크립트의 문제점을 해결해주는데요, 한번 살펴보겠습니다.

statisfies operator

다음 object literal 변수 palette를 보세요. bluebleu로 써버렸네요.

const palette = {
    red: [255, 0, 0],
    green: "#00ff00",
    bleu: [0, 0, 255] 
  // ^^^ 오타!
};

오타를 방지하고 싶습니다.

type Colors = "red" | "green" | "blue";

type RGB = [red: number, green: number, blue: number];

const palette: Record<Colors, string | RGB> = {
    red: [255, 0, 0],
    green: "#00ff00",
    bleu: [0, 0, 255]
//  ~~~~ The typo is now correctly detected
};

하지만 오타를 위해 타입 추론이 아닌 palette 타입을 명시적으로 지정한다면 blue와 red 키 값의 value는 이제 string | RGB 유니온 타입이기 때문에 Array.prototype 이하 api를 사용할 수 없게 되었습니다. string 타입일 경우 Array.prototype.* 메소드를 호출할 수 없기 때문입니다.

statisfies 를 사용할 경우 유니온 타입과 호환되는 타입의 메소드 호출 시도 시 정적 에러를 발생시키지 않습니다. blue의 오타를 발견함과 동시에 value의 메소드를 사용할 수 있는 것이죠.

const palette = {
    red: [255, 0, 0],
    green: "#00ff00",
    bleu: [0, 0, 255]
//  ~~~~ The typo is now caught!
} satisfies Record<Colors, string | RGB>;

// Both of these methods are still accessible!
const greenNormalized = palette.green.toUpperCase();

감을 잡기 위해서 좀 더 알아보겠습니다.

palettered, green, blue 세 가지의 키만 가지게 하려고 하는데요,

// Ensure that we have exactly the keys from 'Colors'.
const favoriteColors = {
    "red": "yes",
    "green": false,
    "blue": "kinda",
    "platypus": false
//  ~~~~~~~~~~ error - "platypus" was never listed in 'Colors'.
} satisfies Record<Colors, boolean | string>;

// All the information about the 'red', 'green', and 'blue' properties are retained.
const g = favoriteColors.green;
// ^^ g: false
const r = favoriteColors.red;
// ^^ r: string
favoriteColors.green = true;
// ^^ Type 'true' is not assignable to type 'false'.(2322)

위 코드를 한번 찬찬히 살펴보세요. platypus 키 바인딩에 대해 에러 표기를 해주는데요,

변수 g의 타입을 보면 false 입니다. boolean이 아니에요.

추후 favoriteColors.green 값에 대해 true 값을 바인딩 하고 싶을 때 favoriteColors.green은 boolean 타입이 아닌 false 타입이기 때문에 에러를 발생시키게 됩니다.

따라서 favoriteColors가 정적 타입 체크에서 freeze object가 아닌 것으로 간주하기 위해서는 다음처럼 해야 합니다.

type Colors = "red" | "green" | "blue";

const favoriteColors = {
    "red": "yes" as const,
    "green": false,
    "blue": "kinda",
} satisfies Record<Colors,unknown>;

// All the information about the 'red', 'green', and 'blue' properties are retained.
const g = favoriteColors.green;
// ^^ g: boolean
const r = favoriteColors.red;
// ^^ r: yes
favoriteColors.green = true;
// ^^ green: boolean

red 키 값에 대해 string 타입이 아닌 "yes" 타입으로 narrow 하게 선언하고 싶다면 as const를 사용하면 그만입니다.

key 값과 상관 없이 value 값만 정적 체크하고 싶으면 다음 처럼 하면 됩니다.

type RGB = [red: number, green: number, blue: number];

const palette = {
    red: [255, 0, 0],
    green: "#00ff00",
    blue: [0, 0]
    //    ~~~~~~ error!
} satisfies Record<string, string | RGB>;

// Information about each property is still maintained.
const redComponent = palette.red.at(0);
const greenNormalized = palette.green.toUpperCase();

PR

statisfies operator와 관련된 PR은 아래에서 확인할 수 있습니다.
https://github.com/microsoft/TypeScript/pull/46827

영향

satisfies and nextjs

nextjs를 만든 회사 vercel의 member Lee Robinson은 statisfies operator가 nextjs에 큰 영향을 준다고 말합니다.

GetStaticProps 타입이 어떻게 되어있는지 한번 봅시다.

제너릭 타입 P가 {[key: string]: any}extends 하기 때문에
Page 컴포넌트에서 props를 추론할 때 실제 getStatiProps에서 리턴하는 object의 id 속성을 제대로 추론하지 못합니다.

이를 statisfies operator를 사용해 정확히 props의 타입을 추론할 수 있게 만들 수 있습니다.

출처: https://twitter.com/leeerob/status/1563540593003106306

글을 마치며

오늘은 typescript 4.9 버전 업데이트 내역 중 satisfies operator에 대해 알아봤습니다.

감사합니다.

profile
성장을 향한 작은 몸부림의 흔적들

3개의 댓글

comment-user-thumbnail
2022년 12월 14일

아니 영향까지 ,, 진짜 만족스럽네요 😋

1개의 답글
comment-user-thumbnail
2023년 6월 27일

안녕하세요,
덕분에 satisfies 연산자에 대해서 조금은 이해할 수 있었습니다.
satisfies 연산자가, 정의한 객체 타입(Record)의, 해당하는 value 타입을 반환하고 찾아주는
연산자로 이해했습니다.

위 글 중에서 문의 사항있어 여쭈어 봅니다.

다음과 같은 문장이 있습니다
'변수 g의 타입을 보면 false 입니다. boolean이 아니에요.'

혹시 어떤 이유에서 변수 g의 타입이 'boolean'이 아니라 'false' 리터럴 타입 인지
추가 설명 부탁 드릴 수 있을까요,

글에서
변수의 g 타입이

Record<Colors, boolean | string>일 경우
false 타입이고

Record<Colors, unknown>일 경우
boolean 타입으로
변경됩니다.

이렇게 g 타입이 변경되는 이유는 무엇 일까요?

감사합니다

답글 달기