깊은바다거북
개발 공부 기록
깊은바다거북
전체 방문자
오늘
어제
  • 분류 전체보기 (219)
    • JAVA (9)
    • JavaScript (15)
    • 스파르타코딩클럽 (11)
      • [내일배움단] 웹개발 종합반 개발일지 (5)
      • [내일배움캠프] 프로젝트와 트러블 슈팅 (6)
    • SQL | NoSQL (4)
    • CS 등등 (0)
    • TIL | WIL (173)
    • 기타 에러 해결 (3)
    • 내 살 길 궁리 (4)

인기 글

최근 글

최근 댓글

태그

  • Binary Tree(이진 트리)
  • 자료 구조
  • 혼자 공부하는 자바스크립트
  • 시간 복잡도
  • 최대 힙(Max Heap)
  • leetcode-cli
  • Inorder Traversal(중위 순회)
  • tree
  • 재귀 함수
  • Leetcode
  • BST(이진 탐색 트리)
  • 프로그래머스
  • Trie
  • 자바스크립트 기초 문법
  • DFS(깊이우선탐색)
  • 자잘한 에러 해결
  • Til
  • BFS(너비우선탐색)
  • 코딩테스트 연습문제
  • POST / GET 요청
  • Preorder Traversal(전위 순회)
  • 01. 미니 프로젝트
  • 최소 힙(Min Heap)
  • TIT (Today I Troubleshot)
  • 팀 프로젝트
  • 점화식(Recurrence Relation)
  • Backtracking(백트래킹)
  • TypeScript
  • 트러블 슈팅 Troubleshooting
  • Linked List
hELLO · Designed By 정상우.
깊은바다거북

개발 공부 기록

TIL | WIL

1/30 월 (keyof typeof 콤보) TIL

2023. 1. 31. 00:17

(타입스크립트 공부중)

배운 것:

  • 타입스크립트에서 keyof typeof 꼼수의 활용례와 원리에 대해 알아봤다.
  • 타입스크립트의 열거형을 Jest를 활용한 테스트코드와 연계하여 연습해보았다.
  • 데이터베이스의 인덱스 개념과 selectivity 이슈, 정규화와 역정규화에 대한 예제를 조금 더 익혔다. 검색 속도를 빠르게 하기 위해 도리어 정규화의 반대 루트(역정규화)를 택할 때도 있다는 사실이 흥미로웠다.


Jest 테스트코드 사용 예제 비교

describe("테스트 큰 제목", () => {
	it("테스트 작은 제목", () => {
		expect(...).toBe(false);
	}
}

vs

describe("테스트 큰 제목", () => {
	test("테스트 작은 제목", async () => {
		expect(...).toEqual(false);
	}
}

it()은 test()와 같다. (test()의 별명)

toBe는 toEqual에 더해 주소값까지 같음을 비교하는 메소드이다.

export enum Status {
  Initialized = "Initialized",
  Pending = "Pending",
  Complete = "Complete",
}

export function isStatusPending(status: Status): boolean {
  return status == Status.Pending;
}

isStatusPending(Status.Pending) // ⇒ Status타입이 와야 하는 자리에 이렇게 넣을 수 있다. type은 Status.Pending이고 근본타입(값)은 "Pending"
= isStatusPending("Pending")
= true

⇒ Status타입이 와야 하는 자리에 이렇게 넣을 수 있다.

typeof 연산자

: 대상의 타입 자체를 나타내줄 수 있도록 만든 연산자.

: 객체, 열거형, 함수 등을 type 형태로 바꿔줌.

: typeof {value에 해당하는 값}

⇒ typeof {객체}

⇒ typeof {enum}

⇒ typeof {함수}

⇒ typeof {클래스}

(typeof {'type'에 해당하는 값}처럼 사용시 ‘value’에 해당하는 값을 넣으라고 컴파일 에러 발생.)

// 간단 예시:
let s = "hello"'
let n: typeof s;
// => let n: string
  1. 객체 → type

    : 객체의 타입 구조를 그대로 뽑아와 새 타입으로 만들어 사용하고 싶을 때 사용.

    const obj = {
       red: 'apple',
       yellow: 'banana',
       green: 'cucumber',
    };
     
    // 위의 객체를 타입으로 변환하여 사용하고 싶을때
    type Fruit = typeof obj;
    /*
    type Fruit = {
        red: string;
        yellow: string;
        green: string;
    }
    */

  1. enum → type

    열거형(Enum)도 타입 구조를 추출할 수 있다.

    enum Color {
      Red,
      Blue,
      Black,
    }
    
    type TColor = typeof Color;
    /*
    type TColor = {
    	Red: number;
    	Blue: number;
    	Black: number;
    }
    */

  1. 함수 → type

    함수의 타입 구조도 뽑아올 수 있다.

    function original(num: number, str: string): string {
    	return num.toString();
    }
    
    type original_Type = typeof original
    // type original_Type = (num: number, str: string) => string
    
    const 용례: original_Type = (num: number, str: string) => {
    	return str;
    };

  1. 클래스 → type

    클래스는 자체가 객체 타입이 될 수 있으므로 typeof를 붙이지 않고도 타입 구조를 뽑아올 수 있다.

    class ClassExample {
    	constructor(public name: string, public age: number) {}
    }
    
    type ClassExample_Type = ClassExample;
    // = type ClassExample_type = { name: string, age: number }
    
    const 용례: ClassExample_Type = {
    	name: '마실',
    	age: 99,
    }

  1. 인터페이스 → type

    인터페이스는 자체가 타입이므로 ‘타입 구조를 뽑는다’는 것이 불가능함.

keyof 연산자

: ‘type(타입)’의 ‘키’들을 뽑아서 문자열 리터럴 유니온 타입으로 만들어 주는 연산자.

: keyof {type에 해당하는 값들}

type과 interface, class에 직접 적용 가능하다.

⇒ keyof {type}

⇒ keyof {interface}

⇒ keyof {class}

(keyof {value에 해당하는 값}처럼 사용시 ‘type’을 넣어달라고 컴파일 에러가 난다.)

  1. (명시적) type → type
type Type = {
   name: string;
   age: number;
   married: boolean;
}
 
type Union = keyof Type;
// type Union = "name" | "age" | "married"

const 용례: Union = 'name';
  1. class → type
class ClassExample {
	constructor(public name: string, public age: number) {}
}

type ClassToKeys = keyof ClassExample;
// type ClassToKeys = "name" | "age"
  1. interface → type
interface IDirection {
   Up: number,
   Down?: number,
   Left?: number,
   Right?: number,
}

type InterfaceToKeys = keyof IDirection;
// type InterfaceToKeys = "Up" | "Down" | "Left" | "Right"

  1. 다른 것들 (객체, enum, 함수 등)은 typeof로 type화를 거쳐야 적용 가능하다.

⇒ (typeof로 변환한) type → type

// typeof 항목에서 봤던 대로 
// 1. 객체 -> (typeof) -> (keyof) -> type

// 2. Enum -> (typeof) -> (keyof) -> type

// 3. 함수 -> 적용되지 않음. 생각해보면 함수의 typeof로 뽑아온 구조는 파라미터의 타입과 리턴값의 타입을 ㅈ어의해 놓은 것인데, 여기서 특별히 'key'라고 할만 한 게 없다. 
function original(num: number, str: string): string {
	return num.toString();
}
type FunctionType = typeof original;
// type FunctionType = (num: number, str: string) => string
type FunctionToKeys = keyof FunctionType
// type FunctionToKeys = never

// 4. 클래스 -> type 
// 과 클래스 -> (typeof) -> (keyof) -> type 이 같음. 
// 중간에 typeof를 거치든 안 거치든 결과가 같다.
// 5. 인터페이스 -> 컴파일 에러.

  • Enum에 적용하면 이상해진다:
    enum EDirection {
       Up,
       Down,
       Left,
       Right,
    }
    
    type strangeType = keyof EDirection;
    // strangeType = "toString" | "toFixed" | "toExponential" | "toPrecision" | "valueOf" | "toLocaleString"

    ⇒ Enum의 경우 typeof를 한 번 거쳐야함을 알게됨.

  • 객체에 적용하면 아예 컴파일이 안 된다:
    const ODirection = {
       Up: 0,
       Down: 1,
       Left: 2,
       Right: 3,
    }
    
    type newOb = keyof ODirection;
    // TS2749: 'ODirection' refers to a value, but is being used as a type here. Did you mean 'typeof ODirection'?

keyof typeof 조합

enum Color {
  Red,
  Blue,
  Black,
}

type TColor = {
  [key in keyof typeof Color]: string[];
}

// 이걸 작동되게 Tcolor를 만들고 싶다.
const colors: TColor = {
  Red: ["red"],
  Blue: [],
  Black: ["obsidian", "ink"],
};

// typeof Color: 
type TColor = {
	Red: number;
	Blue: number;
	Black: number;
}

// keyof typeof Color: 
type TColor = "Red" | "Blue" | "Black"

// [key in keyof typeof Color] 적용 후:
type TColor = {
	"Red": string[],
	"Blue": string[],
	"Black": string[],
}

keyof Color로 한 번에 키들을 빼오고 싶어도, keyof는 객체 형태에만(=type이나 객체인 형태. enum은 안됨.) 작용하므로 먼저 typeof로 ‘type’ 형태로 만들어주고, 그 후에 keyof를 적용시키는 꼼수이다.

한 마디로 정리하자면, keyof typeof Enum은, ‘Enum을 먼저 type으로 변환시킨 후 key 목록 추출’인 것.

종류:

// typeof 항목과 keyof 항목에서 살펴본 것 요약본: 
 
// 1. 객체 -> (typeof) -> (keyof) -> type
// 2. Enum -> (typeof) -> (keyof) -> type
// 3. 함수 -> 적용되지 않음. 
// 4-1. 클래스 -> type 
// 4-2. 클래스 -> (typeof) -> (keyof) -> type 
//    (클래스는 중간에 typeof를 거치든 안 거치든 결과가 같다.)

객체에서 ‘key’ 추출

객체의 ‘key’값들을 리터럴 유니온 타입(상수 타입)으로 뽑아내고 싶다면:

const obj = { red: 'apple', yellow: 'banana', green: 'cucumber' } as const; 

type Keys = keyof typeof obj; 
// type Keys = "red" | "green" | "yellow"

let ob2: Keys = 'red';
let ob3: Keys = 'yellow';
let ob4: Keys = 'green';

객체에서 ‘value’ 추출

객체의 ‘value’값들을 리터럴 유니온 타입(상수 타입)으로 뽑아내고 싶다면:

const obj = { red: 'apple', yellow: 'banana', green: 'cucumber' } as const;

type Values = typeof obj[keyof typeof obj];  
// type Values = "apple" | "cucumber" | "banana"

let ob2: Values = 'apple';
let ob3: Values = 'banana';
let ob4: Values = 'cucumber';


Uploaded by N2T

    'TIL | WIL' 카테고리의 다른 글
    • 2/1 수 (4번째 프로젝트 시작) TIL
    • 1/31 화 (타입스크립트 엔티티 모음과 분류) TIL, TIT
    • 1/29 일 (열거형과 제네릭) TIL
    • 1/28 토 (2차원 배열 만들기, 반복문 순회 대상 업데이트하기) TIL, TIT
    깊은바다거북
    깊은바다거북

    티스토리툴바