jineecode

Typescript 유틸리티 본문

JS/Typescript(공개용)

Typescript 유틸리티

지니코딩 2022. 7. 11. 15:04

연관이 있는 import type !

import type {FC, ComponentProps, ForwardRefRenderFunction} from 'react';
import type {StyleProp, TextStyle} from 'react-native';

 

ComponentProps

React(-Native)의 특정 컴포넌트에서 쓰이는 props 의 타입들을 별도의 타입으로 선언해서 사용하고 싶으면 아래와 같이 작성.

export type TextInputProps = ComponentProps<typeof 컴포넌트이름>;
// EX

export type TextInputProps = ComponentProps<typeof TextInput>;

export const Inputs: FC<TextInputProps> = () => {
  return <TextInput />;
};

 

위 값을 상속받아 다른 값도 추가적으로 더하고 싶으면 아래와 같이 작성한다.

export type TextInputProps = ComponentProps<typeof 컴포넌트이름> & {
  name: string;
  age: number;
};

 

Partial<T>

타입 T의 모든 프로퍼티를 Optional 형태로 바꾸어줍니다.

type Partial<T> = { [P in keyof T]?: T[P]; };

오른쪽에서 P in keyof T는 타입 T의 프로퍼티 키값에 해당하는 P를 전부 옵셔널(물음표 키워드) 형태로 감싸 리턴한다.

Partial은 타입은 원시 타입에 해당하는 프토 퍼티 값을 할당할 수도 안 할 수도 있지만 원시 타입에 존재하지 않는 값은 할당할 수 없음.

interface User {
    name: string;
    age: number;
}

let user1: User = {name: 'harry', age: 23} //OK
let user2: User = {age: 23} // 에러발생

let user2: Partial<User> = {age: 23} // OK

 

Require<T>

모든 Optional 타입들을 언랩핑합니다.

type Required<T> = {
    [P in keyof T]-?: T[P];
};

마이너스 연산자는 옵셔널을 제거해주는 연산자이다.

partials에서 물음표 연산자만 사용한 것처럼 플러스 연산자를 생략할 수 있다.

type MutableRequired<T> = { -readonly [P in keyof T]-?: T[P] };  // readonly, optional 제거 
type ReadonlyPartial<T> = { +readonly [P in keyof T]+?: T[P] };  // readonly, optional 추가
interface Props {
    a?: number;
    b?: string;
};

const obj: Props = { a: 5 }; // OK

const obj2: Required<Props> = { a: 5 }; //에러발생

 

Readonly<T>

모든 프로퍼티를 값을 참조만 할 수 있도록 바꿉니다.

type Readonly<T> = { readonly [P in keyof T]: T[P];};
interface Card {
    name: string;
    price: number
}

type readOnlyCard = Readonly<Card>;
let readonlyUser: readOnlyCard = {name: 'Sonata', price: 10000}
readonlyUser.price = 3 // 에러발생

 

Record<K, T>

K타입을 Key값 타입으로, T타입을 밸류 값 타입으로 갖는 타입을 리턴합니다.

type Record<K extends keyof any, T> = {
    [P in K]: T;
};
export interface ValueCar {
    name: string,
    price: number
}

const productList: Record<"SONATA" | "AVANTE", ValueCar> = {
    SONATA: {name: "SONATA", price: 10000},
    AVANTE: {name: "SONATA", price: 10000}
}

const nextProductList: Record<string, ValueCar> = {
    SONATA: {name: "SONATA", price: 10000},
    AVANTE1: {name: "SONATA", price: 10000},
    AVANTE2: {name: "SONATA", price: 10000},
    AVANTE3: {name: "SONATA", price: 10000},
}

 

type memo = { content: string, date: string }
const FRIENDS_LIST = ["harry", "jason", "dukkey"] as const
type FriendTypeArray = typeof FRIENDS_LIST[number];
type friendType = Record<FriendTypeArray, memo>

 

Pick<T, K>

T 타입으로부터 K 프로퍼티만 추출합니다.

type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};
interface Todo {
    title: string;
    description: string;
    completed: boolean;
}

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

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

 

Exclude<T, U>

T 타입들중 U타입들과 겹치는 타입을 제외합니다.

type Exclude<T, U> = T extends U ? never : T;
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

 

Extract<T, U>

T타입에서 U타입과 겹치는 타입만을 가져옵니다.

type Extract<T, U> = T extends U ? T : never;

Exclude와 거의 비슷하지만 T와 never의 위치만 다르기 때문에 교집합을 리턴합니다.

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

 

Omit<T, K>

Pick과는 정반대로 T타입으로부터 K프토퍼티를 제거합니다.

 

type Car = {
    name: string;
    price: number;
    brand: string;
};

//Car에 속하는 Key값들중 brand를 키값으로 갖지않는 프로퍼티들을 
//RemainingKey에 넣습니다.
type RemainingKeys = Exclude<keyof Car, "brand">;

//Car에서 RemaningKeys에 속하는 키값에 속하는 프로퍼티들을 리턴합니다 
type NoBrandCard = Pick<Car, RemainingKeys>;
//결과 type NoBrandCard = { name: string; age: number; };
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>


interface Test {
    a: string;
    b: number;
    c: boolean;
}


type OmitA = Omit<Test, "a">; // Equivalent to: {b: number, c: boolean}
type OmitAB = Omit<Test, "a"|"b">; // Equivalent to: {c: boolean}

 

NonNullable<T>

T타입에서 null or undefinded을 제외하고 리턴합니다.

type NonNullable<T> = T extends null | undefined ? never : T;
type T0 = NonNullable<string | number | undefined>;  // string | number
type T1 = NonNullable<string[] | null | undefined>;  // string[]

 

Parameters<T>

함수의 파라미터를 타입으로 리턴합니다.

declare function f1(arg: { a: number, b: string }): void
type T0 = Parameters<() => string>;  // []
type T1 = Parameters<(s: string) => void>;  // [string]
type T2 = Parameters<(<T>(arg: T) => T)>;  // [unknown]
type T4 = Parameters<typeof f1>;  // { a: number, b: string }
type T5 = Parameters<any>;  // unknown[]

// never는 any를 제외한 모든 타입의 원시타입이기때문에
// 함수타입 T에 never로 주어도 에러가 발생하지 않고
// 인자값으로도 어떠한 값이든 올 수 있기때문에 any가 리턴됩니다.
type T6 = Parameters<never>;  // any

// T extends (...args: any) => any에서
// never 타입을통해 에러를 막지않았기떄문에 함수가 아니라면 에러가 발생합니다.
type T7 = Parameters<string>;  // Error
type T8 = Parameters<Function>;  // Error

 

ReturnType<T>

함수의 리턴타입을 가져옵니다.

let f1 = () => ({ a: 23, b: 33 });
type T0 = ReturnType<() => string>;  // string
type T1 = ReturnType<(s: string) => void>;  // void
type T2 = ReturnType<(<T>() => T)>;  // {}
type T3 = ReturnType<(<T extends U, U extends number[]>() => T)>;  // number[]
type T4 = ReturnType<typeof f1>;  // { a: number, b: string }

 

https://medium.com/harrythegreat/typescript-%EC%9C%A0%ED%8B%B8%EB%A6%AC%ED%8B%B0-%ED%81%B4%EB%9E%98%EC%8A%A4-%ED%8C%8C%ED%97%A4%EC%B9%98%EA%B8%B0-7ae8a786fb20

 

Comments