keyof

정의

객체 타입의 키들을 유니언 타입으로 반환함. 객체의 모든 키를 타입 수준에서 다루고자 할 때 유용하게 사용

 

keyof 주의점

하지만 typeof를 사용할땐 주의점이 필요하다. 간혹 type에 사용하지 않고, const나 let과 같은 변수에 사용하는데, 이와 같은 경우에는 에러가 발생하므로 주의하자.

 

결론 : keyof는 변수 or 객체 리터럴에는 할당이 불가능함, type에만 할당가능함

 

type에만 할당 가능 예제1)

const obj = { a: 1, b: 2, c: 3,}; 
type TypeOfObj = typeof obj; // { a: number, b: number, c: number }
type Key = keyof typeof obj; // "a" | "b" | "c"

type에만 할당 가능 예제2)

type obj = { a: number, b: string};
type Key = keyof obj // "a" | "b"

변수 or 객체 리터럴의 할당 못하는 경우의 예제)

const obj = { a: 1, b: 2, c: 3,}; // const는 변수
type Key = keyof obj // X 오류 발생

typeof

정의

반적인 자바스크립트 변수의 런타임 타입을 반환하는 데 사용한다. 타입스크립트에서 변수나 객체의 타입을 추론하는 데 주로 사용한다.

일반적인 자바스크립트에서 사용

const numberValue = 42;
console.log(typeof numberValue); // "number"

타입스크립트에서의 사용

예제1)

const user = {
    username: "alice",
    email: "alice@example.com",
};

type UserType = typeof user; // { username: string; email: string; }\\

예제2)

const obj = { a: 1, b: 2, c: 3,}; 
type TypeOfObj = typeof obj; // { a: number, b: number, c: number }

Recoil SelectorFamily에 대해 알아보려 한다.

 

정의

Recoil 공식 사이트에 SelectorFamily에 대해 다음과 같이 정의가 되어있다.

A selectorFamily is a powerful pattern that is similar to a selector, but allows you to pass parameters to the get and set callbacks of a selector. The selectorFamily() utility returns a function which can be called with user-defined parameters and returns a selector. Each unique parameter value will return the same memoized selector instance.

 

해당 글을 번역기를 돌려보면 다음과 같다.

selectorFamily는 강력한 패턴으로, selector와 유사하지만 get 및 set 콜백에 매개변수를 전달할 수 있다는 점에서 차이가 있습니다. selectorFamily() 유틸리티는 사용자 정의 매개변수를 사용하여 호출될 수 있는 함수를 반환하며, 그 결과로 selector를 반환합니다. 각 고유한 매개변수 값에 대해 동일한 메모이제이션된 selector 인스턴스를 반환합니다.

 

즉. Recoil Selector와 차이점은 매개 변수를 넣을 수 있다는 것이다.

 

사용법 알아보기

 

다음은 atoms라는 파일에 RecoilState를 examState 정의하고, 

selectorFamily를 examSelector라는 이름으로 정의하였다.

 

atoms.ts

export const examState = atom<number[]>({
  key: "exam"
  default: [1, 2, 3]
});

export const examSelector = selectorFamily({
  key: "examKey",
  get:
    ({ param1, param2 }: { num1: number; num2: number}) => // {param1, param2} 객체로 써주기
    ({ get }) => {
      const nums = get(examState);
      const result = nums.map((num)=> num1 * param2 * param2));
      return result
    },
});

 

위의 코드를 간단하게 설명하면, param1 param2를 객체 형태로 매개 변수로 받고 examState 배열 안의 원소 값에 param1 param2를 곱해주는 것이다. 참고로 매개변수로 보낼 때는 객체 형태로 해줘야 한다는 것을 잊지 말자.

 

컴포넌트에서 사용할 때는 다음과 같다.

 

Home.tsx

export default function Home() {
  const exam = useRecoilValue(examSelector({ num1 : 3, num2: 4 }));
  console.log(exam); // [1 * 3 * 4, 2 * 3 * 4, 3 * 3 * 4]

  return (
    <>
      <>
        <ExamPage exam={exam}>
        />
      </>
    </>
  );
}

 

먼저 위에서 정의한 selectorFamily를 사용하기 위해서는 다음과 같이 불러오면 된다.
useRecoilValue(selectorFamily(객체 매개변수));  ex) useRecoilValue(examSelector({ num1 : 3, num2: 4 }));

def solution(my_string):
    alpa = []

    for i in range(65, 91):
        alpa.append(chr(i))
    for i in range(97,123):
        alpa.append(chr(i))
    # alpa : [A,B,C,D, ....Z, a, b, c, d, ...., z]
    
    result = []
    for item in alpa:
        result.append(my_string.count(item))
    return result

https://school.programmers.co.kr/learn/courses/30/lessons/181902

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

 

설명

A~Z, a~z까지 alpa라는 리스트에 추가를 먼저했다.

그리고 alpa리스트안에 알파벳을 각 순회하면서 count함수를 사용해서 result라는 함수에 추가했다.

HTTP 헤더 종류

HTTP 요청 헤더는 클라이언트가 서버로 요청을 보낼 때 요청에 대한 추가적인 정보를 담고 있는 부분. 이 정보는 요청의 목적이나 특성을 서버에 알려주는 데 사용됨. 헤더는 5가지가 있는데, 다음과 같음. User-Agent, Accept, Content-Type, Authorization, Cookie, Host가 존재하며, 6가지의 알아볼 예정

User-Agent

클라이언트 소프트웨어의 종류와 버전을 식별하기 위한 헤더, 이를 통해 서버는 클라이언트의 종류에 따라 다른 응답을 제공할 수 있음

클라이언트 종류란?

User-Agent는 클라이언트 소프트웨어가 서버로 요청을 보낼 때 사용되는 헤더 중 하나입니다. 이 헤더에는 클라이언트 소프트웨어의 종류와 버전 정보가 포함됩니다. 이 정보는 주로 웹 브라우저, 웹 크롤러, API 클라이언트 등과 같이 다양한 클라이언트 소프트웨어를 식별하는 데 사용됨

예를 들어, 일반적인 브라우저인 Google Chrome은 다음과 같은 User-Agent를 갖게 될 수 있음

Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36

Accept

클라이언트가 서버로부터 어떤 유형의 콘텐츠를 받기를 원하는지를 나타내는 헤더, 이를 통해 서버는 적절한 콘텐츠 유형을 선택하여 응답할 수 있습니다.

여기서 컨텐츠란 무엇인가?

"컨텐츠"란 웹 서버에서 클라이언트에게 전송되는 정보나 자원을 일컫음. 이는 주로 HTML 문서, 이미지, 비디오, 오디오, 텍스트 파일, JSON 데이터 등 다양한 형태의 데이터를 포함할 수 있습니다.

예를 들어, 클라이언트가 JSON 형식의 데이터를 받기를 원하는 경우에는 다음과 같이 Accept 헤더를 설정할 수 있음

Accept: application/json

또는 클라이언트가 텍스트 형식의 HTML 문서를 받기를 원하는 경우에는 다음과 같이 설정할 수 있음

Accept: text/html

Content-Type

클라이언트가 서버에게 보내는 데이터의 유형을 나타내는 헤더, 주로 POST 요청과 함께 사용되며, 서버는 이를 통해 수신된 데이터를 올바르게 처리할 수 있음

Authorization

클라이언트가 서버로 인증 정보를 보내는 데 사용되는 헤더, 주로 사용자 이름과 비밀번호를 포함하여 인증 토큰을 서버에게 전달하는 데 사용됩니다. 예를 들어, HTTP Basic 인증을 사용하는 경우 다음과 같이 Authorization 헤더를 설정할 수 있음

Authorization: Basic QWxhZGRpbjpPcGVuU2VzYW1l

이렇게 하면 서버는 클라이언트의 인증 정보를 확인하여 요청을 인증하고 처리할 수 있음

Cookie

클라이언트가 서버에게 쿠키를 전송하는 데 사용되는 헤더입니다. 서버는 이를 통해 클라이언트의 상태를 추적하고 유지할 수 있습니다. 작은 데이터 조각이며, 클라이언트는 이 쿠키를 다음 요청에 포함하여 서버에게 전달하므로, 서버는 클라이언트의 상태를 파악하고 필요한 서비스를 제공할 수 있음

Host

클라이언트가 요청을 보내는 서버의 호스트 이름과 포트를 나타내는 헤더입니다. 여러 개의 도메인이 호스팅되는 경우 해당 도메인을 식별하는 데 사용됩니다. 예를 들어, www.example.com 도메인으로 요청을 보내는 경우 다음과 같이 Host 헤더를 설정할 수 있음

오른쪽 Navbar 상단위에 유저 정보를 클릭시 로그인, 회원가입 드랍다운이 가능하도록 구현하였다.

Ant design + tailwindcss를 사용하였으며, 코드는 다음과 같다.

 

navbar.tsx

import styled from "@emotion/styled";
import { Modal } from "antd";
import { ReactNode } from "react";
import Line from "../../../common/liine/line";

interface BaseModalProps {
  children: ReactNode;
  isModalOpen: boolean;
  title: string;
  onCancel: () => void;
}

const AuthModal = styled(Modal)`
  .ant-modal-title {
    font-size: 15epx;
    text-align: center;
  }
`;

function Footer(): JSX.Element {
  return (
    <>
      <div className="flex justify-center">
        <button className="w-full h-12 text-white bg-pink-700 rounded-lg border-none">
          계속
        </button>
      </div>
    </>
  );
}

export default function AuthLayout({
  children,
  title,
  isModalOpen,
  onCancel,
}: BaseModalProps): JSX.Element {
  return (
    <>
      <AuthModal
        title={title}
        open={isModalOpen}
        centered={true}
        width={530}
        footer={Footer}
        onCancel={onCancel}
      >
        <Line />
        <h2 className="text-xl font-semibold mt-5">
          에어비엔비에 오신걸 환영합니다.
        </h2>
        {children}
      </AuthModal>
    </>
  );
}

 

user.tsx

 

import { useState } from "react";
import LoginModal from "../../units/modals/auth/login_modal";
import SignupModal from "../../units/modals/auth/signup_modal";
import Search from "./search";
import User from "./user";

export default function Navbar(): JSX.Element {
  const [loginModalOpend, setLoginModalOpend] = useState(false);
  const [signupModalOpend, setSignupModalOpend] = useState(false);
  const handleSignup = (): void => {
    setSignupModalOpend((prev) => !prev);
  };

  const handleLogin = (): void => {
    setLoginModalOpend((prev) => !prev);
  };

  return (
    <>
      <nav className="w-full h-40 bg-white font-semibold pt-4">
        <div className="flex justify-between items-center">
          <h2 className="text-red-500 text-2xl">airbnb</h2>
          <User handleSignup={handleSignup} handleLogin={handleLogin} />
        </div>
        <Search />
      </nav>
      {loginModalOpend ? (
        <LoginModal
          loginModalOpend={loginModalOpend}
          handleLogin={handleLogin}
        />
      ) : (
        ""
      )}
      {signupModalOpend ? (
        <SignupModal
          signupModalOpend={signupModalOpend}
          handleSignup={handleSignup}
        />
      ) : (
        ""
      )}
    </>
  );
}

 

 

실제 결과

 

 

 

<모달 구현>

 

layout.tsx

import { faBars } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import React from "react";
import { Dropdown, Space, Typography } from "antd";
import type { MenuProps } from "antd";

interface UserProps {
  handleSignup: () => void;
  handleLogin: () => void;
}

export default function User({
  handleSignup,
  handleLogin,
}: UserProps): JSX.Element {
  const items: MenuProps["items"] = [
    {
      key: "1",
      label: "로그인",
      style: { height: "50%", backgroundColor: "white", color: "black" },
      onClick: () => {
        handleLogin();
      },
    },
    {
      key: "2",
      label: "회원가입",
      style: {
        height: "50%",
        backgroundColor: "white",
        color: "black",
      },
      onClick: () => {
        handleSignup();
      },
    },
  ];

  return (
    <>
      <Dropdown
        menu={{
          items,
          selectable: true,
          defaultSelectedKeys: ["1"],
          style: { width: "220px", height: "100px" },
        }}
      >
        <Typography.Link>
          <Space>
            <button className="w-24 h-12 flex justify-between items-center border rounded-full pl-3 pr-3">
              <FontAwesomeIcon icon={faBars} />
              <image className="w-1/2 h-3/4 flex justify-center items-center bg-black rounded-full text-white text-sm">
                U
              </image>
            </button>
          </Space>
        </Typography.Link>
      </Dropdown>
    </>
  );
}

 

signup_modal.tsx

 

import { Input } from "antd";
import AuthLayout from "./layout";

interface SignupProps {
  signupModalOpend: boolean;
  handleSignup: () => void;
}

export default function SignupModal({
  signupModalOpend,
  handleSignup,
}: SignupProps): JSX.Element {
  return (
    <>
      <AuthLayout
        title="로그인 또는 회원가입"
        isModalOpen={signupModalOpend}
        onCancel={handleSignup}
      >
        <form className="space-y-3 mt-5">
          <Input placeholder="이메일" className="h-10" />
          <Input placeholder="이름" className="h-10" />
          <Input placeholder="휴대폰번호" className="h-10" />
          <Input.Password placeholder="패스워드" className="h-10" />
          <Input.Password placeholder="패스워드 확인" className="h-10" />
        </form>
      </AuthLayout>
    </>
  );
}

 

login_modal.tsx

import { Input } from "antd";
import AuthLayout from "./layout";

interface LoginProps {
  loginModalOpend: boolean;
  handleLogin: () => void;
}

export default function LoginModal({
  loginModalOpend,
  handleLogin,
}: LoginProps): JSX.Element {
  return (
    <>
      <AuthLayout
        title="로그인 또는 회원가입"
        isModalOpen={loginModalOpend}
        onCancel={handleLogin}
      >
        <form className="space-y-3 mt-4">
          <Input placeholder="이메일" className="h-10" />
          <Input.Password placeholder="패스워드" className="h-10" />
        </form>
      </AuthLayout>
    </>
  );
}

 

 

 

결과

회원가입 모달

 

사진1

 

사진2
사진3

 

에어비엔비 tailwindcss를 활용하여, Room Detail 페이지를 구현하였다. 전반적인 틀만 만들었고, 기능구현하면서 따로 스타일링을 추가적으로 할예정이다. 

function main() {
  const filePath = process.platform === "linux" ? "/dev/stdin" : "ex.txt";
  const [n, inputs, v] = require("fs")
    .readFileSync(filePath)
    .toString()
    .trim()
    .split("\n");
  console.log(inputs.split(" ").filter((item) => item === v).length);
}

main();

https://www.acmicpc.net/problem/10814

 

10814번: 나이순 정렬

온라인 저지에 가입한 사람들의 나이와 이름이 가입한 순서대로 주어진다. 이때, 회원들을 나이가 증가하는 순으로, 나이가 같으면 먼저 가입한 사람이 앞에 오는 순서로 정렬하는 프로그램을

www.acmicpc.net

const filePath = process.platform === "linux" ? "/dev/stdin" : "ex.txt";
const [n, ...lines] = require("fs")
  .readFileSync(filePath)
  .toString()
  .trim()
  .split("\n");

let users = [];

lines.forEach((line, index) => {
  const [age, name] = line.split(" ");
  users.push({ age: parseInt(age), name, index });
});

users.sort((a, b) => a.age - b.age);

users.forEach(({ age, name }) => {
  console.log(`${age} ${name}`);
});

+ Recent posts