본문 바로가기
공부/Typescript

유틸리티 타입

by nr2p 2022. 12. 11.
반응형

a.  Partial<T>

  • T의 모든 프로퍼티들을 옵셔널하게 만드는 유틸리티 타입

b. Readonly<T>

  • T의 모든 프로퍼티들을 읽기 전용(readonly)으로 만드는 유틸리티 타입

interface Palette {
  [key: string] : string
}

const gray: Readonly<Palette> = {
  '001': '#111111',
  '002': '#999999',
}

// frozen 객체의 프로퍼티에 재할당하려고 하는 경우
function freeze<T>(obj: T): Readonly<T>;

c. Record<K,T>

  • 타입 T의 프로퍼티의 집합 K로 타입을 구성

// 객체의 key 와 value의 타입을 따로따로 정의 가능
interface PageInfo {
    title: string;
}

type Page = 'home' | 'about' | 'contact';

const x: Record<Page, PageInfo> = {
    about: { title: 'about' },
    contact: { title: 'contact' },
    home: { title: 'home' },
};

d. Pick<T,K>

  • T에서 프로퍼티 K의 집합을 선택해 타입을 구성

interface Todo {
    title: string;
    description: string;
    completed: boolean;
}

type TodoPreview = Pick<Todo, 'title' | 'completed'>;

const todo: TodoPreview = {
    title: 'Clean room',
    completed: false,
};

e. Omit<T,K>

  • T에서 모든 프로퍼티를 선택한 다음 K를 제거한 타입을 구성

interface Todo {
    title: string;
    description: string;
    completed: boolean;
}

type TodoPreview = Omit<Todo, 'description'>;

const todo: TodoPreview = {
    title: 'Clean room',
    completed: false,
}

// yup TestContext 내의 parent 의 타입을 정의
// 기존 타입과 겹치는 타입을 제거 후 추가된 프로퍼티의 타입을 추가
interface ThumbnailTestContext extends Omit<TestContext, 'parent'> {
  parent: Thumbnail
}

type ThumbnailTestContext = Omit<TestContext, 'parent'> & {parent: Thumbnail}

f. Exclude<T,U>

  • T에서 U에 할당할 수 있는 모든 속성을 제외한 타입을 구성

type T0 = Exclude<"a" | "b" | "c", "a">;  // "b" | "c"
type T1 = Exclude<"a" | "b" | "c", "a" | "b">;  // "c"
type T2 = Exclude<string | number | (() => void), Function>;  // string | number

g. Extract<T,U>

  • T에서 U에 할당 할 수 있는 모든 속성을 추출하여 타입을 구성

type T0 = Extract<"a" | "b" | "c", "a" | "f">;  // "a"
type T1 = Extract<string | number | (() => void), Function>;  // () => void

h. NonNullable<T>

  • T에서 null과 undefined를 제외한 타입을 구성

type T0 = NonNullable<string | number | undefined>;  // string | number
type T1 = NonNullable<string[] | null | undefined>;  // string[]

// NonNullable 을 Exclude 유틸을 사용해서 구현할 수도 있다.
type NonNullable2<T> = Exclude<T, undefined | null>

i. Parameters<T>

  • 함수 타입 T의 매개변수 타입들의 튜플 타입을 구성

declare function getSomethingActive(info: {id: string, state: boolean}): void
type Params = Parameters<typeof getSomethingActive>;
// [{id: string, state: boolean}]

-> infer 이 Parameters 와 같은 유틸을 만들 때 유용하게 사용됨

j. ConstructorParameters<T>

  • 생성자 함수 타입의 모든 매개변수 타입을 추출
  • Parameters 와 비슷하지만 생성자임을 확인하기 위한 abstract new 가 추가로 붙었다.

class User {
  constructor (name: string, tier: 'GOLD' | 'SILVER') {}
}

const muzi = new User('Muzi', 'GOLD');
const a: ConstructorParameters<typeof User> = ['Muzi', 'GOLD'];
const b: ConstructorParameters<typeof User> = ['Lion']; // type error..

k. ReturnType<T>

  • 함수 T의 반환 타입으로 구성된 타입

declare function f1(): { a: number, b: string }

type T0 = ReturnType<typeof f1>;  // { a: number, b: string }

l. InstanceType<T>

  • 생성자 함수 타입 T의 인스턴스 타입으로 구성된 타입

class User {
  x = 'x'
  constructor(public name: string) {}
}

class User2 {
  x = 0;
  constructor(public name: string) {}
}

const user: InstanceType<typeof User> = new User('name');
const user2: InstanceType<typeof User> = new User2('name');

m. Required<T>

  • T의 모든 프로퍼티가 필수로 설정된 타입을 구성
  • -? : Mapping Modifiers 의 하나로 옵셔널을 제거 (링크)

interface Props {
    a?: number;
    b?: string;
};

const obj: Props = { a: 5 }; // 성공

const obj2: Required<Props> = { a: 5 }; // 오류: 프로퍼티 'b'가 없습니다

n. ThisParameterType

  • 함수 타입의 this 매개변수의 타입, 혹은 함수 타입에 this 매개변수가 없을 경우
  • unknown 을 추출합니다
  • --strictFunctionTypes가 활성화되었을 때만 올바르게 동작함

function toHex(this: Number) {
    return this.toString(16);
}

function numberToString(n: ThisParameterType<typeof toHex>) {
    return toHex.apply(n);
}

o. OmitThisParameter

  • 함수 타입에서 'this' 매개변수를 제거
  • --strictFunctionTypes가 활성화되었을 때만 올바르게 동작함

function getAge(this: typeof cat) {
  return this.age;
}

// 기존 데이터
const cat = {
  age: 12 // Number
};
getAge.call(cat); // 12

// 새로운 데이터
const dog = {
  age: '13' // String
};
getAge.call(dog); // TS2345: Argument of type '{ age: string; }' is not assignable to parameter of type '{ age: number; }'.

const getAgeForDog: OmitThisParameter<typeof getAge> = getAge;
getAgeForDog.call(dog); // '13'

p. ThisType<T>

  • 이 유틸리티는 변형된 타입을 반환하지 않는 대신, 문맥적 this타입에 표시하는 역할을 함
  • --noImplicitThis플래그를 사용해야 함
interface IUser {
  name: string,
  getName: () => string
}

function makeNeo(methods: ThisType<IUser>) {
// ThisType이 타입을 반환하지 않기 때문에 타입 단언을 사용하여 타입이 추론되게끔 하였다.
  return { name: 'Neo', ...methods } as IUser;
}
const neo = makeNeo({
  getName() {
    return this.name;
  }
});

neo.getName(); // Neo

 느낀점

- 유틸타입을 적극적으로 사용하면 좀 더 명시적인 타이핑이 가능할 것 같다.

- extends, infer 의 쓰임새에 대해서  좀 더 이해하게 되었다. 특히 infer 의 경우 언제 쓸지 정말 궁금했는데 이럴 때 쓰는거구나 하고 느끼게 됨

- Mapping Modifiers 을 처음 알게 되었다.


 

출처

반응형