nokia's blog

타입을 사용하여 타입 구성하기

2022-07-11

타입스크립트 공부를 하면서 어려운 점 중 하나는 value의 관점이 아닌 해당 value의 타입의 관점으로 봐야한다는 점 같습니다.
타입을 이용해 새로운 타입을 만드는 여러가지 방법을 타입스크립트 공식 문서를 참고하며 정리해 보았습니다.

keyof Type Operator

object 타입의 키를 문자열, 혹은 숫자 리터럴 타입으로 반환합니다.
object 타입이 여러개의 키를 갖는다면 이를 유니온 타입으로 반환합니다.

type Person = {
  name: string;
  age: number;
  address: string;
};
 
type PersonKeys = keyof Person;
 
const personName: PersonKeys = "name";
const personAge: PersonKeys = "age";
const personAddress: PersonKeys = "address";
// OK
 
const personSalary: PersonKeys = "salary";
// Error

위에서 선언한 타입은 PersonKeys = 'name' | 'age' | 'address'로 표현한 것과 같습니다.

typeof Type Operator

typeof는 변수의 값의 type을 반환하는 키워드 입니다.
타입이 아닌 변수나 함수와 같은 의 타입을 얻어내야 할 때 사용합니다.

function foo() {
  return { x: 10, y: 3 };
}
 
type FooReturn = ReturnType<foo>;
// Error
 
type FooReturn = ReturnType<typeof foo>;
// type FooReturn = { x: number, y: number }
 
const coordinate1: FooReturn = { x: 10, y: 24 };
// OK
const coordinate2: FooReturn = { x: 10, y: "24" };
// Error

Indexed Access Types

object 타입의 키의 타입을 참조할 수 있습니다.
배열의 index를 통해 값을 접근할 수 있듯이 object의 타입을 키를 통해 타입에 접근이 가능합니다.
키를 유니온으로 표현할 경우 키 타입들의 유니온 타입이됩니다.

type Person = {
  name: string;
  age: number;
  isFemale: boolean;
};
 
type Gender = Person["isFemale"];
 
const bool1: Gender = true;
const bool2: Gender = false;
// OK
 
const num: Gender = 1;
// Error
 
type ObjectProperty = Person["name" | "age"];
 
const key1: ObjectProperty = 1;
const key2: ObjectProperty = "1";
// OK
 
const key3: ObjectProperty = true;
// Error

Person의 name키의 타입은 string, age키의 타입은 number이기 때문에 ObjectProperty 타입은 이를 union으로 표현한 number | string이 됩니다.

배열 요소의 타입을 'number'키를 이용하여 접근하기

const Villagers = [
  { name: "John", age: 20 },
  { name: "Jane", age: 23 },
  { name: "James", age: 17 },
];
 
type Villager = (typeof Villagers)[number];
// { name: string, age: number };
type Age = (typeof Villagers)[number]["age"];
// string
type Name = (typeof Villagers)[number]["name"];
// string

Conditional Types

삼항연산자를 이용하면 condition에 따라 다른 타입을 지정할 수 있습니다.

SomeType extends OtherType ? TrueType : FalseType; 메서드를 여러 타입의 input을 위해 오버로딩할 때 비슷하게 생긴 여러개의 코드를 생성해야 합니다. 이 때 conditional type을 통해 이를 간결하게 표현할 수 있습니다.

interface IdLabel {
	id: number;
}
 
interface NameLabel {
	name: string;
}
 
function createLabel(id: number): IdLabel;
function createLabel(name: string): NameLabel;
function createLabel(nameOrId: string | number)
	: IdLabel | NameLabel;
 
// using conditional type
 
type IdOrNameLabel<T extends string | number> =
T extends number ? IdLabel : NameLabel;
// T의 타입이 number이면 IdLabel 타입, 아니면 NameLabel 타입을 반환
 
function createLabel<T extend string | number>(idOrName: T)
	: IdOrNameLabel<T>

// to do

한계

Inferring within conditional types

Mapped Types

참고자료

typescript - Creating Types from Types
typescript - Mapped Types

Related Posts