The Basic Cheatsheet

์ „์ œ ์กฐ๊ฑด

์ „์ œ ์กฐ๊ฑด์„ ๋ณด๋ฉด์„œ ์•Œ๊ฒŒ ๋œ ์‚ฌ์‹ค ์ •๋ฆฌ

TypeScript์˜ ์žฅ์ 

  1. TypeScript๋ฅผ ์“ด๋‹ค๋ฉด JavaScript์—์„œ unit test๋ฅผ ์“ธ ํ•„์š”๊ฐ€ ์—†๋‹ค. TypeScript๊ฐ€ ์ž๋™์ ์œผ๋กœ ์ฒดํฌํ•ด ์ค€๋‹ค.

  2. This is especially useful when youโ€™re using a UI library and need to transform data. For example, if youโ€™re using React, youโ€™ll need to transform data in state updates.

we can use mapped types like Readonly to convert one type to another type.

   // Readonly<...> makes each property readonly
   type Todo = Readonly<{
     id: number
     text: string
     done: boolean
   }>

   // ์œ„ <...>์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.
   type Todo = {
     readonly id: number
     readonly text: string
     readonly done: boolean
   }

readonly๋Š” array์˜ push์™€๋„ ๊ฐ™์ด ์“ฐ์ผ ์ˆ˜ ์žˆ๋‹ค.

Type assertions

let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
// as Type์„ ๋” ์ถ”์ฒœํ•œ๋‹ค.
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;

์ถœ์ฒ˜ https://ts.chibicode.com/todo/

Function Components

Hooks

https://github.com/DefinitelyTyped/DefinitelyTyped/blob/a05cc538a42243c632f054e42eab483ebf1560ab/types/react/index.d.ts#L800-L1031

useState

const [user, setUser] = React.useState<IUser | null>(null);

default value์ธ null๊ณผ ํ•จ๊ป˜ |๋ฅผ ์‚ฌ์šฉํ•˜๋Š” union type์„ ๋งŽ์€ hook๋“ค์€ ์‚ฌ์šฉํ•œ๋‹ค.

useRef

initial value๊ฐ€ ์—†๋Š” ref container ์ƒ์„ฑํ•  ๋•Œ

const ref1 = useRef<HTMLElement>(null!);
const ref2 = useRef<HTMLElement | null>(null);
  • ref1๋Š” readonly์šฉ react๊ฐ€ ๊ด€๋ฆฌํ•  built-in ref attributes์— ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ? (Response handles for your current value setting)

  • ref2๋Š” ref2.current๋ฅผ mutableํ•˜๊ฒŒ ํ•ด์ฃผ๊ณ  ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘๊ด€๋ฆฌํ•˜๋Š” instance variables ๋ฅผ ์œ„ํ•œ ๊ฒƒ์ด๋‹ค.

๋„ค? ๋ญ๋ผ๊ตฌ์—ฌ???

useEffect

ํ•จ์ˆ˜ ๋˜๋Š” undefined ์ด์™ธ์— ๋‹ค๋ฅธ ๊ฒƒ์ด return ๋˜์ง€ ์•Š๋„๋ก ์ฃผ์˜ํ•œ๋‹ค.

setTimeout์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ number๊ฐ€ return๋˜๊ธฐ ๋•Œ๋ฌธ์— curly brace๋กœ ๊ผญ ๊ฐ์‹ธ์ž.

useRef

function TextInputWithFocusButton() {
  // ์ดˆ๊ธฐ๊ฐ’์€ null, HTMLInputElement๋ฅผ ์ฐพ๊ณ  ์žˆ๋‹ค๊ณ  TypeScript์— ๋งํ•จ
  const inputEl = React.useRef<HTMLInputElement>(null);
  const onButtonClick = () => {
    // strict null ์ฒดํฌ๋Š” inputEl์™€ current๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธํ•ด์•ผํ•œ๋‹ค.
    // ์กด์žฌํ•˜๋ฉด HTMLInputElement type์ด๋ฏ€๋กœ ๋”ฐ๋ผ์„œ method focus๋ฅผ ๊ฐ€์ง„๋‹ค. ๐Ÿ™‚ Yay
    if (inputEl && inputEl.current) {
      inputEl.current.focus();
    }
  };
  return (
    <>
      {/* ๋˜ํ•œ inputEl๋Š” input์š”์†Œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค? focus ๋•Œ๋ฌธ์ธ๊ฐ€ */}
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}

useReducer

reducer action์„ Discriminated Unions ์‚ฌ์šฉํ•œ๋‹ค. return type์„ ์ •์˜ํ•˜๋Š” ๊ฒƒ์„ ์ ˆ๋Œ€ ์žŠ์ง€๋ง์ž.

type AppState = {};
type Action =
  | { type: "SET_ONE"; payload: string }
  | { type: "SET_TWO"; payload: number };

export function reducer(state: AppState, action: Action): AppState {
  switch (action.type) {
    case "SET_ONE":
      return {
        ...state,
        one: action.payload, // `payload` is string
      };
    case "SET_TWO":
      return {
        ...state,
        two: action.payload, // `payload` is number
      };
    default:
      return state;
  }
}

Discriminated Unions(์œ ๋‹ˆ์˜จ ์‹๋ณ„)์€ singleton types, union types, type guards, ๋ฐ type aliases์„ ๊ฒฐํ•ฉํ•˜์—ฌ discriminated unions, tagged unions, ๋˜๋Š” algebraic(๋Œ€์ˆ˜์˜) data type์œผ๋กœ ๋ถˆ๋ฆฌ๋Š” ๊ณ ๊ธ‰ ํŒจํ„ด์„ ๋นŒ๋“œํ•  ์ˆ˜ ์žˆ๋‹ค.

interface Square {
  kind: "square";
  size: number;
}
interface Rectangle {
  kind: "rectangle";
  width: number;
  height: number;
}
interface Circle {
  kind: "circle";
  radius: number;
}

๊ฒฐํ•ฉํ•  interface๋ฅผ ์„ ์–ธํ•œ๋‹ค.

๊ณตํ†ต์ ์œผ๋กœ kind๋ผ๋Š” ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”๋ฐ ์ด๋ฅผ discriminant ํ˜น์€ tag๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค.

type Shape = Square | Rectangle | Circle;

๊ฒฐํ•ฉ์“ฐ

function area(s: Shape) {
    switch (s.kind) {
        case "square": return s.size * s.size;
        case "rectangle": return s.height * s.width;
        case "circle": return Math.PI * s.radius ** 2;
    }
}

discriminated union์„ ์‚ฌ์šฉํ•˜์ž!

useReducer์—์„œ๋Š” type์ด discriminant ํ˜น์€ tag๊ฐ€ ๋˜๋Š” ๊ฒƒ์ด๊ณ 

์ด์ „์— ๋ดค๋˜ ์ฝ”๋“œ๋“ค์„ ์ƒ๊ฐํ•˜๋ฉด App component์—์„œ status ๋ฅผ ์˜ˆ์‹œ๋กœ ๋“ค ์ˆ˜ ์žˆ์„ ๊ฑฐ ๊ฐ™๋‹ค.๐Ÿคญ

export interface VerifyingAuth {
  status: 'verifying';
}

export interface UnsignedAuth {
  status: 'unsigned';
  inProgress?: 'signing';
  error?: Error;
}

export interface SignedAuth {
  status: 'signed';
  inProgress?: 'passwordChanging' | 'unsigning';
  error?: Error;
  token: string;
  user: UserInfo;
}
export type Auth = VerifyingAuth | UnsignedAuth | SignedAuth;
<AuthProvider api={api}>
  {(auth: Auth) => {
    switch (auth.status) {
      case 'verifying':
        return <div>...verifying</div>;
      case 'unsigned':
        return (
          <Switch>
            <Route exact path="/" component={LoginPage} />
            <Redirect to="/" />
          </Switch>
        );
      case 'signed':
        return (
          <MissionProvider>
            <Switch>
              <Route path="/dashboard" component={DashboardPage} />
              <Route path="/missions/:missionId" component={MissionPage} />
              <Redirect to="/dashboard" />
            </Switch>
          </MissionProvider>
        );
      default:
        return <div>Unknown auth status...</div>;
    }
  }}
</AuthProvider>

Custom Hooks

Last updated

Was this helpful?