jtwjs Dev Wiki
  • DEV_ROAD
    • 💪🏻 생존하기
    • Week 1
      • 개발 환경 세팅
      • 타입스크립트
      • 리엑트
      • Testing Library
      • Parcel & ESLint
    • Week 2
      • JSX
      • Virtual DOM
    • Week 3
      • React Component
      • React State
    • Week 4
      • Express
      • Fetch API & CORS
      • React Hook
      • useRef & Custom Hook
    • Week 5
      • TDD
      • React Testing Library
      • MSW
      • Playwrite
      • Snapshot
    • Week 6
      • Separtion of Concerns
      • Principle
      • DI, (Dependency Injection)
      • Reflect-metadata
      • TSyringe
      • External Store
      • Follow Redux
      • usestore-ts
      • useSyncExternalStore
    • Week 7
      • Routing
      • Routes
      • Router
      • Navigation
    • Week 8
      • Design System
      • Style Basics
      • CSS-in-JS
      • Styled-Components
      • Global Style & Theme
    • Week 9
      • 개발하기 전 준비
      • 상품 목록 페이지
      • 상품 상세 페이지
      • 장바구니 페이지
    • Week 10
      • 로그인
      • 로그아웃
      • 회원가입
      • 주문 목록 & 주문 상세
    • Week 11
      • 배송 정보 입력
      • 포트원 결제 요청
      • 배송 및 결제 정보 전달
    • Week 12
      • 관리자 웹사이트개발시작
  • DEV_NOTE
    • TypeScript
      • 기본적 문법
        • Enum
        • 다형성
          • Untitled
        • 구조적 타이핑
        • 제너릭 타입
        • 컨디셔널 타입
        • 함수 메서드 타이핑
        • infer로 타입스크립트의 추론 직접 활용
        • 재귀 타입
        • 템플릿 리터럴 타입
        • 추가적인 타입 검사 satisfies 연산자
        • 타입스크립트 건망증
        • 원시 자료형에도 브랜딩 기법 사용 가능
        • 타입 좁히기
        • 유용한 타입 만들기
        • 데코레이터 함수
        • 앰비언트 선언도 선언 병합이 된다.
        • 앰비언트 선언도 선언병합이 된다.
    • Testing
      • Unit Testing
      • 단위 테스트의 두 분파
      • 좋은 단위 테스트를 구성하는 4대 요소
      • 테스트 대역과 식별할 수 있는 동작
      • 단위 테스트 스타일
      • 가치 있는 단위 테스트를 위한 리팩토링
      • 통합 테스트
      • Cross Browsing Testing
      • 기능 테스트 종류
      • React Testing Pattern
      • 프론트엔드 테스트 입문
        • 테스트 범위
        • 단위 테스트 검증
        • Mock
        • UI 컴포넌트 테스트
        • 테스트 커버리지
        • 웹 통합 테스트
        • MSW
        • 스토리북
        • 시각적 회귀 테스트
        • E2E 테스트
        • Github Actions 설정
        • 깃허브 액션에서 E2E
      • 시프트 레프트
        • 테스트 기본중의 기본
        • 단위 테스트
        • 코드 복잡도
        • 리팩터링
        • 코드 리뷰
        • 통합 테스트 패턴
        • 시스템 테스트의 자동화
        • 탐색적 테스트
      • Test Tip
      • vitest
      • playwright
      • Test Data Generator
      • MSW
    • Algorithm
      • coding test
      • Data Structure
    • Next.js
      • Data Fetching
      • Hydration
      • Next 13
      • Optimization
      • Next 15
    • Tailwind
      • Tailwind CSS
      • Theme
      • Directives
      • Tool
      • Design System
    • Storybook
      • Storybook
      • CSF3
      • CDD
      • Headless Component
    • Funtional Programming
      • 함수형 프로그래밍
      • 참조 투명성
      • 부수효과
      • 함수 합성
      • 제너릭 타입 활용하기
      • 암묵적 입출력
      • 액션과 계산, 데이터
      • 계층형 설계
      • 호출 그래프
      • 함수형 설계
      • 불변성
      • 일급 함수
      • 함수형 도구
    • Git
      • Github Actions
      • Conflict
      • Branch 전략
    • Contents Format
      • Audio
    • 3D Graphic
      • 3D keyword
      • Three.js
      • Geometry
      • Material
      • Light
      • Camera
      • Decal
      • Rotation
      • Text
      • Shadow
      • Fog
      • Post Processing
      • Animation
      • Math
        • Vector Space
        • 벡터의 연산
        • 회전 계산
      • 3D 컨텐츠가 만들어지는 과정
      • R3F
      • Env
      • Scene
      • Transform
      • R3F
      • Interaction & Raycast
      • Rendering Algorithnm
      • Blender
      • Blender
    • Accessibility
      • 접근성이란
    • Interactive Web
      • Parallax
      • Canvas
      • requestAnimationFrame
      • Effect
      • HSL
      • React.js + Canvas
      • Matter.js
    • AWS
      • DevOps
      • Amplify
      • S3
      • 클라우드 컴퓨팅
        • 온프레미스와 클라우드
        • 클라우드 도입효과
        • 클라우드 컴퓨팅의 범위
        • 컴퓨팅 옵션
          • EC2 - Virtual Machin
          • ECS, EKS - Container
          • Lambda - Serverless
        • 네트워크 가상화
        • 스토리지
        • 데이터베이스
        • 데이터 수집
        • 머신 러닝 영역
        • IoT 영역
        • 블록체인 영역
      • 클라우드 아키텍처 설계
    • Network
      • Web Server & WAS
    • System Design
      • System Design
      • Component
      • 의존성을 배제한 개발
      • Error Handling
      • Architecture
        • 모노로틱 아키텍처
        • Clean Architecture
        • Layered Architecture
        • 이벤트 기반 아키텍처
      • 상황을 파악하는 메타인지
      • 중복 문제 해결하기
      • Monorepo Arhitecture
        • 모노레포 운영과 트러블슈팅
        • Module Federation
      • 코드 병목지점
      • API 대응
      • 공통 코드
      • Infra 구축
      • 모듈 기반의 개발 방식
      • Design System
        • 최소 수준의 아키텍처 설정
        • 더 효율적인 디자인시스템 만들기
        • 디자인 시스템과 UI 라이브러리 목적
        • 디자인 토큰
      • 효율적인 업무
        • 업무 프로세스 병목 파악
      • Clean Code
      • Design Pattern
        • CQRS Pattern
        • Strangler Fig Pattern
        • 데코레이터 패턴
        • 커맨드 패턴
        • 전략 패턴
        • 옵저버 패턴
      • A/B 테스팅
      • 대규모 리엑트 웹앱 개발
        • 복잡성 관리
        • 모듈성
        • 성능
        • 디자인 시스템
        • 데이터 패칭
        • 상태 관리
        • 국제화
        • 코드 조직화하기
        • 개인화 A/B 테스팅
        • 확장 가능한 웹 아키텍처
        • 테스팅
        • 툴링
        • 기술적 마이그레이션
        • 타입스크립트
        • 라우팅
        • 사용자 중심 API 디자인
        • 리액트 미래
    • Performance
      • React DevTools
      • Component 최적화
      • Page Load
      • API
    • MFA
      • MSA
      • MFA 도입하기
      • Monorepo
        • Monorepo Tool
        • Yarn Berry Workspace
        • Turborepo
      • MFA Composition
      • SPA 통합
      • Design System
      • Package Manager
        • Yarn
        • pnpm
      • Transpiler & Bundler
        • Babel
        • Rollup
        • esbuild
        • swc
        • Webpack
        • Vite
      • 분해와 통합을 위한 여러 기술 비교
    • State Management
      • Zustand
    • React v18
      • Automatic batching
      • Suspense
      • Transition
    • SEO
      • Search Engine Optimization
      • Open Graph Element
      • Metadata
    • FE Develop
      • Scrubbing
      • Clipboard
    • Refactoring
      • 리팩토링 깊게 들여다보기
      • 긴 코드 조각내기
      • 타입 코드 처리하기
      • 유사한 코드 융합하기
      • 데이터 보호
      • 코드 추가 및 제거
    • OAuth 2.0
    • Analytics
      • Mixpanel
    • ETC
      • VSCode
    • React Hook In Action
      • useContext & Provider
      • 커스텀 훅
      • 코드 분할하기 with Suspense, lazy
      • Suspense와 이미지 적재하기
      • useTransition, uesDeferredValue
      • SuspenseList
Powered by GitBook
On this page
  • 핵심 포인트
  • 컨디셔널 타입
  • 컨디셔널 타입은 never와 함께 사용할 때 도 많다.
  • 매핑된 객체 타입에서 키가 never 이면 해당 속성은 제거된다.
  • 중첩 삼항연산자
  • 분배 법칙
  • 분배법칙을 막고 싶다면?
  • never도 분배법칙의 대상이 된다.
  1. DEV_NOTE
  2. TypeScript
  3. 기본적 문법

컨디셔널 타입

핵심 포인트

  • 컨디셔널 타입에 never를 사용할 때가 많은데 제너릭과 같이 쓸 때에만 의미가 있다.

  • 매핑된 객체 타입에서 키가 never 이면 해당 속성은 제거된다.

  • 검사하려는 타입이 제너릭이면서 유니언이면 분배법칙이 실행됨

  • boolean은 분배법칙이 일어나면 true | false 로 인식하게 된다.

  • 분배법칙을 막고 싶다면 배열로 감싸라

  • never도 분배법칙의 대상이 된다. -> never는 유니언으로 보이진 않지만 유니언으로 생각하는것이 좋다.

    • never는 분배법칙이 일어나면 never 가 된다.

    • 간단하게 제너릭과 never가 만나면 never가 된다고 생각하자.

    • never를 타입인수로 사용할 때는 분배법칙을 막기 위해 배열로 감싸라

  • 타입스크립트는 제너릭이 들어있는 컨디셔널 타입을 판단할 때 값의 판단을 뒤로 미룬다.

    • 이 때도 타입스크립트가 판단을 뒤로 미루지 못하도록 배열로 제너릭을 감싸면 된다.

컨디셔널 타입

조건에 따라 다른 타입이되는 컨디셔널 타입

type A1 = string;
type B1 = A1 extends string ? number : boolean; // type B1 = number

type A2 = number;
type B2 = A2 extends string ? number : boolean; // type B2 = boolean
  • extends 연산자가 삼항연산자와 같이 사용됨

    • 특정 타입 extends 다른 타입 ? 참일 때 타입 : 거짓일 때 타입

  • 특정 타입이 다른 타입의 부분집합일 때 참

  • 컨디셔널 타입은 타입 검사를 위해서도 많이 사용함

컨디셔널 타입은 never와 함께 사용할 때 도 많다.

보통은 제너릭과 더불어 쓸 때만 never가 의미가 있다.

type Start = string | number;
type New = Start extends string | number ? Start[] : never;
let n: New = ['hi'];
n = [123];
  • ❓ 그냥 type New = Start[] 로 사용해도 되지 않나??

    • 사실 그렇다.

    • 단순한 상황에서는 never 와 함께 쓸 이유가 없다.

    • 보통은 제너릭과 더불어 쓸 때만 never가 의미가 있다.

type ChooseArray<A> = A extends string ? string[] : never;
type StringArray = ChooseArray<string>; // type StringARray = string[]
type Never = ChoosArray<number>; // type Never = never;

never 타입은 모든 타입에 대입할 수 있기에 모든 타입을 extends 할 수 있다.

type Result = never extends string ? true : false; // type Result = true

매핑된 객체 타입에서 키가 never 이면 해당 속성은 제거된다.

type OmitByType<O, T> = {
  [K in keyof O as O[K] extends T ? never : K]: O[K];
}
type Result = OmitByType<{ // type Result = { name: string, age: number }
  name: string;
  age: number;
  married: boolean;
  rich: boolean;
}, boolean>

중첩 삼항연산자

컨디셔널 타입은 자바스크립트 삼항연산자처럼 중첩해서 만들기 가능

type ChooseArray<A> = A extends string 
  ? string[]
  : A extends boolean ? boolean[] : never;
type StringArray = ChooseArray<string>; // string[]
type BooleanArray = ChooseArray<boolean>; // boolean[]
type Never = ChooseArray<number>; // never
  • 인덱스 접근 타입으로 컨디셔널 타입을 표현 가능

type A1 = string;
// B1 타입과 B2 타입은 같음
type B1 = A1 extends string ? number : boolean;
// B2 처럼 왜 굳이 복잡하게 사용하냐면, 참일 때와 거짓일 때의 타입이 복잡한 경우는 아래처럼 나타내기도 함
type B2 = {
  't': number;
  'f': boolean;
}[A1 extends string ? 't' : 'f']

분배 법칙

제너릭과 never의 조합은 더 복잡한 상황에서 진가를 발휘함

  • string | number 타입으로부터 string[] 타입을 얻고 싶을 때?

type Start = string | number;
// string | number 가 string을 extends 할 수 없기 때문
// string이 더 구체적이므로 대입 불가능 
type Result = Start extends string ? Start[] : never; // never

// 컨디셔널 타입을 제너릭과 함께 사용하면 원하는 동작 가능
type Start = string | number;
type Result<Key> = Key extends string ? Key[] : never;
let n: Result<Start> = ['hi']; // let n: string[]
  • 검사하려는 타입이 제너릭이면서 유니언이면 분배법칙이 실행됨

    • Result<string | number>는 Result<string> | Result<number> 가 된다.

    • 따라서 Key extends string | boolean ? Key[] : never를 거치면서 string [] | never가 되고 never는 사라져서 최종적으로 string[] 타입이 된 것

  • boolean에 분배법칙이 적용될 떄는 조심!!

    • boolean을 true | false 로 인식하게 된다.

type Start = string | number | boolean;
type Result<Key> = Key extends string | boolean ? Key[] : never;
let n: Result<Strart> = ['hi']; // string[] | false[] | true[]
n = [true];

분배법칙을 막고 싶다면?

배열로 감싸면 분배법칙이 일어나지 않는다.

type IsString<T> = T extends string ? true : false;
// 분배법칙에 의해 IsString<'h1'> | IsString<3> -> true | false => boolean
type Result = IsString<'h1' | 3>; // type Result = boolean

// 배열로 감싼 경우
type IsString<T> = [T] extends [string] ? true : false;
type Result = IsString<'h1' | 3>; //  type Result = false

never도 분배법칙의 대상이 된다.

never가 유니언으로 보이지는 않지만 유니언으로 생각하는것이 좋다.

never가 분배법칙이 일어나면 never가 된다. (공집합에서 분배법칙이 일어나면 아무것도 실행하지 않기때문)

type R<T> = T extends string ? true : false;
// 분배법칙이 일어나서 true가 아니라 never가 됨
type RR = R<never>; // type RR = never
  • never는 공집합과 같으므로 공집합에서 분배법칙을 실행하는 것은 아무것도 실행하지 않는것과 같다.

  • 간단하게 제너릭과 never가 만나면 never가 된다고 생각하자.

  • 따라서 never를 타입인수로 사용하려면 분배법칙이 일어나는것을 막아야 한다.

type IsNever<T> = [T] extends [never] ? true : false;
type T = isNever<never>; // Type T = true
type F = isNever<'never'>; // Type F = false
  • 같은 이유로 제너릭과 컨디셔널 타입을 같이 사용할 때는 다음을 조심하자.

    • 타입스크립트는 제너릭이 들어있는 컨디셔널 타입을 판단할 때 값의 판단을 뒤로 미룬다.

    • 이 때도 타입스크립트가 판단을 뒤로 미루지 못하도록 배열로 제너릭을 감싸면 된다.

function test<T>(a: T) {
  type R<T> = T extends string ? T : T; // R<T> 타입이 T 타입이 될거라고 생각하는게 잘못됨
  // 즉, 변수 b에 매개변수 a를 대입할 때까지도 타입스크립트는 R<T>가 T 라는것을 알지 못한다.
  const b: R<T> = a; // type 'T' is not assignable to type 'R<T>'
}

// 제너릭을 배열로 감싸면 타입 판단을 뒤로 미루지 않게됨
// 타입 매개변수를 선언할 때 바로 <[T] extends [string]> 하는것이 불가능하므로
// 한 번 더 컨디셔널 타입으로 묶어서 선언한 것
function test<T extends ([T] extends [string] ? string : never)>(a: T) {
  type R<T> = [T] extends [string] ? T : T;
  const b: R<T> = a;
}

컨디셔널 타입은 infer를 통해 더 강력하게 사용 가능

Previous제너릭 타입Next함수 메서드 타이핑

Last updated 5 months ago