BBZJUN's
[하나은행] Digital hana 路
JAVA
J1
JavaScript
NEXT
N1
N2
N3_강재준의 과제2셋팅
React
R1
R2
R3
R4 copy
R4
SQL
Spring
TypeScript
T1
T2
T3
T4
공부
JavaScript
기술면접
프론트엔드
코딩테스트
백준
코드트리
알고리즘이름(1)
알고리즘이름(2)
JAVA개념
Home
Contact
Copyright © 2024 |
Yankos
BBZJUN
> [하나은행] Digital hana 路
...
[하나은행] Digital hana 路
Spring
Spring 개발환경세팅 https://start.spring.io/ 접속 세팅 Gradle - Groovy Java 3.3.5 DependenciesAdd ... * Thymeleaf Template Engines * Spring Web Web 후 다운받아서 파일을 압축풀고, 인텔리제이로 열어서 진행
[하나은행] Digital hana 路
· 2024-11-21
MySQL
MySQL 개발환경세팅 1. sql 폴더 생성 ex) mkdir sql 2. docker-compose.yml 파일을 sql 폴더 안에 생성하기 docker-compose.yml 내용 > <<< services: localdb: container_name: hana4db image: mysql:8.0 ports: - 3309:3306 environment: MYSQL_ROOT_PASSWORD: TestdbRoot MYSQL_DATABASE: testdb command: - --character-set-server=utf8mb4 - --collation-server=utf8mb4_unicode_ci - --log_bin_trust_function_creators=1 volumes: - ./mysql:/var/lib/mysql >>> 공유 디렉토리 만들기 sql 폴더 안에 mysql이라는 폴더를 만들어서(위의 volumes가 공유폴더이름) ``shell $> docker compose up -d ⇐⇒ docker-compose up -d down (container 제거) $> docker-compose down 확인 $> docker ps cf. 시작만 (docker compose stop) $> docker compose start 완전삭제: -volumne, -stop, -force volumes: $> docker compose rm -vsf # mysql 접속하기 ```shell mysql -u root -p // 3306포트면 mysql -u root -p -P 3309 //포트가 다를경우 뒤에 -P 쓰고 포트 걸어주기 use mysql로 mysql로 접속하기 데이터 넣어주기 sql파일을 해당 폴더 안에 넣고 mysql -u root -p -P 3309(3306이 기본이라 필요없으면 -p까지만 쓴다 ) testdb(해당db이름) < testdb_sample.sql(파일이름)
[하나은행] Digital hana 路
· 2024-11-18
JAVA
자바 (인테리제이 초반 설정) 인텔리제이 설정 플러그인(Plugins) CheckStyle-IDEA > JAVA로 하는 ESLINT 같은 느낌 > setting에서 CheckStyle설정하기 naver checks를 다운 받아서 CheckStyle에서 +버튼으로 rule을 등록한다 그리고 같이 다운 받은 xml파일을 value에 파일명으로 넣어준다 https://github.com/naver/hackday-conventions-java/blob/master/rule-config/naver-checkstyle-rules.xml https://github.com/naver/hackday-conventions-java/blob/master/rule-config/naver-checkstyle-suppressions.xml > Code style도 들어가서 java에서 설정할것 Scheme에서 받은 네이버 파일 열어서 쓰기 https://github.com/naver/hackday-conventions-java/blob/master/rule-config/naver-intellij-formatter.xml 다운받은파일 그리고 action들어가서 세이브 할때마다 프리티어 적용되게 설정하기 optimize imports 체크 Reformat code 체크 system settings들어가서 자동 저장 설정 Atom Material Icons > 깔끔한 아이콘 보기 Key promoter X > VSCode Keymap > Material Theme > 테마 설정가능 터미널에서 자바실행하는 방법 해당 자바파일이 있는 곳에서 javac 파일이름.java 하면 파일이름.class가 생긴다 여기서 이제 java 파일이름.java 하면 터미널에서 실행이 된다 package com.hana.greetings; import java.util.Scanner; public class Hi { public static void main(String[] args) { scanTemp(); >>메인에다가 이렇게 쓰고 알트+엔터로 크리에이트메소드로 뺀다! } >>그러면 아래처럼 생긴다! private static void scanTemp() { Scanner scan = new Scanner(System.in); System.out.println(); } } 자바 args[]에 값을 넣고 실행하기 javac 이름.java java 패키지.이름 args[] 으로arg[]값을 넣어서 실행가능 또는 인텔리제이의 윗창에서 current file의 오른쪽에있는 ...(세로)를 눌러서 거기에 값을 넣고 실행을 해주면 된다 접근 제어자 public - 모든 클래스에서 접근 가능 protected - 같은 패키지 또는 자식 클래스에서 접근 가능 private - 같은 클래스 내에서만 접근 가능 제너릭 public class Box<T> { private T item; public void setItem(T item) { this.item = item; } } 자바의 제너릭(Generic)은 코드의 재사용성을 높이기 위해 특정 데이터 타입을 미리 정의하지 않고, 런타임에 사용할 수 있도록 만든 기능입니다. 제너릭을 사용하면 코드의 안정성을 높이면서 타입 변환을 줄일 수 있어 컴파일 시 오류를 줄일 수 있습니다. 여기서 는 타입 파라미터를 의미하며, 다양한 타입을 하나의 클래스, 메서드, 인터페이스에서 사용할 수 있도록 합니다. 제너릭 안에서는 static으로 T를 선언하면 오류를 제너릭 에서 static T는 컴파일 오류가 뜬다. why? static 멤버는 클래스 로딩 시점에 메모리에 로드되기 때문에, 제네릭 타입 파라미터 T와 같이 인스턴스에 따라 달라지는 타입 정보를 가질 수 없습니다. <? super T>: 하위 타입 한정 와일드카드 - 특정 타입 T와 그 상위 타입만 허용, 주로 데이터를 넣을 때 사용됨 <?>: 비한정 와일드카드 - 비한정 와일드카드로 모든 타입을 허용, 주로 읽기 전용으로 사용할 때 유용 <? extends T>: 상위 타입 한정 와일드카드 - 특정 타입 T와 그 하위 타입만 허용, 주로 데이터를 읽기 전용으로 사용할 때 사용됨 도 있다 StringBuffer 자바에서 문자열을 효율적으로 수정할 수 있도록 만들어진 클래스입니다. String은 불변(immutable) 클래스라서 한 번 생성되면 내용이 바뀌지 않지만, StringBuffer는 가변(mutable) 클래스이기 때문에 문자열을 수정, 추가, 삭제하는 작업에 유리합니다. 주요 메서드 append(): 문자열을 뒤에 추가 insert(): 특정 위치에 문자열 삽입 delete(): 특정 범위의 문자열 삭제 reverse(): 문자열을 뒤집음 toString(): StringBuffer 객체를 String으로 변환 ```javapublic class Main { public static void main(String[] args) { StringBuffer sb = new StringBuffer(“Hello”); sb.append(" World"); // "Hello World"로 수정 System.out.println(sb); // 출력: Hello World sb.insert(6, "Java "); // "Hello Java World"로 수정 System.out.println(sb); // 출력: Hello Java World sb.delete(6, 11); // "Hello World"로 수정 System.out.println(sb); // 출력: Hello World sb.reverse(); // "dlroW olleH"로 수정 System.out.println(sb); // 출력: dlroW olleH } } ``` 콜렉션
[하나은행] Digital hana 路
· 2024-10-31
NEXT
NEXT https://nextjs.org/learn NEXT 14를 사용하자 리액트 베이스의 풀스택이다! 생성 pnpm dlx create-next-app@latest What is your project named? my-app Would you like to use TypeScript? No / Yes Would you like to use ESLint? No / Yes Would you like to use Tailwind CSS? No / Yes Would you like to use src/ directory? No / Yes Would you like to use App Router? (recommended) No / Yes Would you like to customize the default import alias (@/)? No / Yes What import alias would you like configured? @/ prettier & eslint-plugin-react pnpm add -D prettier eslint-config-prettier pnpm add -D eslint-plugin-react eslint-plugin-react-hooks @next/eslint-plugin-next .eslintrc.json { "extends": ["next/core-web-vitals", "prettier", "plugin:react/recommended", "plugin:react/jsx-runtime", "plugin:react-hooks/recommended"] } pnpm add -D @trivago/prettier-plugin-sort-imports .prettierrc { "singleQuote": true, "jsxSingleQuote": true, "semi": true, "trailingComma": "es5", "plugins": ["@trivago/prettier-plugin-sort-imports"], "importOrder": [ "^next$", "^next/\\w*$", "^next/(.*)$", "^react$", "^react/(.*)$", "^@/lib/(.*)$", "^[./]" ] } 프리티어 테스트 $> pnpm format >> 오류 뜨면 pnpm format --write >> 로 설정잡기 빌드(스타트) pnpm build >>빌드먼저 해주고 pnpm start next-auth v5 $> pnpm add next-auth@beta >> 설치 $> pnpm dlx auth secret >> 키 생성 (.env.local)
[하나은행] Digital hana 路
· 2024-10-11
NEXT
NEXT https://nextjs.org/learn NEXT 14를 사용하자 리액트 베이스의 풀스택이다! 폴더가 라우터다 (폴더이름)내 맘대로 만들고 그안에 들어가는 구성요소는 page, layout, template 이름 고정이다 ex) about 폴더 1. mkdir app/about (Route Folder) 2. make app/about/layout.tsx 3. make app/about/page.tsx 4. nav to page from Home(app/page.tsx) 서버에서 이루어진다. 위쪽에 “use client”는 Next.js 13 이상에서 도입된 기능으로, 컴포넌트가 클라이언트 컴포넌트임을 명시하는 선언입니다. 프리티어(위에 임포트 순서 설정) .prettierrc { "singleQuote": true, "jsxSingleQuote": true, "semi": true, "trailingComma": "es5", "plugins": ["@trivago/prettier-plugin-sort-imports"], "importOrder": [ "^next$", "^next/\\w*$", "^next/(.*)$", "^react$", "^react/(.*)$", "^@/lib/(.*)$", "^[./]" ] } >에서 importOrder의 내부 순서를 바꾸어주면 import되는것들의 순서를 지정해줄 수 있다. yarn dev yarn build -> yarn start 차이를 알아두기(dev에서는 계속 시간같은거 업데이트 가능하지만, start에서는 배포용이라서 딱 그 시점?이 올라감, 따라서 다이나믹하게 만들어줘야함) useRouter (only Client Component) 'use client'; > 이거는 이제 클라이언트(=브라우저)에서 실행이 되게끔한다!!! //클라이언트 컴포넌트에서는 어싱크(async)를 못 쓴다. // useRouter import { useRouter } from 'next/navigation' const router = useRouter() router.push('/dashboard', { scroll: false }); // another functions router.back(); useSearchParam ?? 다이나믹하게 페이지 // /hi/[time]/page.tsx export default function HiTime({ params }: { params: { time: string } }) { return <div>Good {params.time}!</div> } ()는 경로에 영향을 미치지 않음(정리용) /app /(auth) /login/page.tsx /dashboard/page.tsx 여기서 (auth)는 그냥 더 가독성 좋게 보일려고하는거임 인터셉트 client router와 server router를 다르게 표현 next/link/Link를 이용해야 intercepting 됨. A → B(intercept) → B(refresh) (.) 같은 레벨/depth (..) 하나 위 레벨 (...) Root 레벨 (..)(..) 두개 위 레벨 원래 원본의 파일이 있는데 그 파일로 이동하는 것이 아닌 내가 만든 인터셉트 페이지로 이동을 시킨다(이것은 새로고침하면 원본페이지로 이동이 된다), (.)/ (..) / (…) 같은경우는 그냥 폴더 위치에 따른 경로 느낌 [[]] 대괄호 두개 [[...params]]와 같은 형태는 Next.js에서 Catch-All 라우팅을 사용할 때, 대괄호를 2개 사용하는 방식입니다. 이것은 동적 경로를 정의할 때 매우 유용합니다. 대괄호 두 개([[...]])는 특정 경로가 **선택적 동적 경로(선택적 Catch-All)**임을 의미합니다. 1. [...params] (Catch-All 라우팅): 설명: [...]를 사용하면 URL의 나머지 부분을 하나의 배열로 캡처할 수 있습니다. 예시: /pages/blog/[...slug].tsx 이 경우, blog 경로의 하위 모든 경로가 slug 배열로 캡처됩니다. 예를 들어: /blog/hello/world → { slug: ['hello', 'world'] } /blog/my-post → { slug: ['my-post'] } 2. [[...params]] (선택적 Catch-All 라우팅): 설명: 대괄호 두 개([[...]])를 사용하면 선택적 동적 경로가 됩니다. 즉, 이 경로는 있어도 되고 없어도 되는 선택적 경로입니다. 예시: /pages/blog/[[...slug]].tsx 이 경우, blog 경로는 동적 경로가 없어도 매칭이 됩니다. 예를 들어: /blog → { slug: [] } (빈 배열) /blog/hello/world → { slug: ['hello', 'world'] } /blog/my-post → { slug: ['my-post'] } 요약: [...params]: Catch-All 동적 경로로서, 지정한 경로 이후의 모든 부분을 배열로 캡처합니다. [[...params]]: 선택적 Catch-All 동적 경로로서, 경로가 있어도 되고 없어도 됩니다. 경로가 없을 경우 빈 배열로 반환됩니다. 이 패턴을 통해 유연한 라우팅을 구성할 수 있으며, 다양한 경로 변형을 처리하는 데 매우 유용합니다. use client 와 asyncs는 같이 사용을 못한다. "use client"와 async 함수는 각자 다른 환경에서 동작하기 때문에, 서버 컴포넌트와 클라이언트 컴포넌트의 특성 차이로 인해 제약이 발생합니다. > 왜 use client와 async를 함께 사용할 수 없을까? 클라이언트 컴포넌트는 동기적으로 렌더링: Next.js에서 클라이언트 컴포넌트는 브라우저에서 동기적으로 렌더링됩니다. 클라이언트 컴포넌트는 동기적인 렌더링 흐름을 가져야 하기 때문에 컴포넌트 자체가 async 함수가 될 수 없습니다. 만약 컴포넌트 전체가 async로 선언되면, 해당 컴포넌트가 반환할 때까지 기다려야 하는데, 이는 브라우저의 동기 렌더링 흐름과 맞지 않기 때문에 에러가 발생합니다. 데이터 가져오기와 렌더링의 분리: 클라이언트 컴포넌트에서는 데이터 가져오기를 위해 React hooks를 사용해야 합니다. useEffect, useState 같은 React hooks로 비동기 작업을 처리하고, 상태 업데이트를 통해 다시 렌더링해야 합니다. 서버 컴포넌트에서는 서버에서 데이터를 미리 가져온 후 그 결과를 클라이언트로 넘겨주지만, 클라이언트 컴포넌트는 브라우저에서 비동기 작업을 별도로 처리하고 렌더링 흐름을 제어해야 합니다. Image를 사용하기 위한 설정 // for Image component in next.config.mjs /** @type {import('next').NextConfig} */ const nextConfig = { images: { remotePatterns: [ { protocol: 'https', hostname: 'via.placeholder.com', port: '', pathname: '/**', }, ], }, }; export default nextConfig; Next Cloudinary Image(사진) 편집??? https://next.cloudinary.dev/ shadcn 설치!!! https://ui.shadcn.com/docs/installation/next pnpm dlx shadcn@latest init 아이콘 패키지 설치!! https://heroicons.com/ $> pnpm add @heroicons/react Next-auth 설치 $> pnpm add next-auth@beta $> pnpm dlx auth secret >> .env.local의 AUTH_SECRET 자동 세팅!
[하나은행] Digital hana 路
· 2024-10-08
NEXT
NEXT https://nextjs.org/learn NEXT 14를 사용하자 리액트 베이스의 풀스택이다! Next.js에서 SSG, SSR, ISR, CSR에 대해 한국어로 설명드리면: SSG (정적 사이트 생성): 설명: SSG는 페이지를 빌드 시점에 미리 렌더링하여 정적인 HTML 파일로 생성합니다. 이렇게 생성된 페이지는 이후 요청 시 서버에서 그대로 제공됩니다. Next.js에서의 동작 방식: getStaticProps와 비슷하며, 이 메서드를 사용해 빌드 시 데이터를 가져와 페이지를 생성합니다. 코드 예시: js 코드 복사 const staticData = await fetch('https://...', { cache: 'force-cache' }); force-cache는 데이터를 빌드 시에만 캐싱하고 이후로는 그대로 제공하는 방식입니다. SSR (서버 사이드 렌더링): 설명: SSR은 매 요청 시 서버에서 페이지를 렌더링하고 HTML을 클라이언트로 전달합니다. 페이지는 사용자 요청마다 새롭게 렌더링되므로, 최신 데이터를 항상 반영합니다. Next.js에서의 동작 방식: getServerSideProps와 유사하며, cache: 'no-store'를 사용하여 서버가 캐싱 없이 매번 새로운 데이터를 받아옵니다. 코드 예시: js 코드 복사 const dynamicData = await fetch('https://...', { cache: 'no-store' }); ISR (증분 정적 재생성): 설명: ISR은 정적 사이트 생성(SSG)와 유사하지만, 지정된 시간 간격으로 페이지를 재생성합니다. 즉, 페이지가 처음에는 정적으로 생성되지만, 설정된 시간(예: 10초)이 지나면 새 데이터를 반영해 페이지를 다시 생성할 수 있습니다. Next.js에서의 동작 방식: getStaticProps에서 revalidate 옵션을 사용하는 방식과 유사하며, 이를 통해 주기적으로 데이터를 다시 가져옵니다. 코드 예시: js 코드 복사 const revalidatedData = await fetch('https://...', { next: { revalidate: 10 } }); 이 예시는 10초마다 데이터를 다시 가져와 페이지를 재생성합니다. CSR (클라이언트 사이드 렌더링): 설명: CSR은 클라이언트에서 모든 페이지를 렌더링하는 방식입니다. 즉, JavaScript가 로드된 후 브라우저에서 데이터를 가져오고 페이지를 렌더링합니다. React의 SPA(단일 페이지 애플리케이션)와 비슷한 방식입니다. Next.js에서의 동작 방식: 페이지 컴포넌트에 'use client';를 선언하면 해당 페이지는 클라이언트 측에서만 렌더링됩니다. 코드 예시: js 코드 복사 'use client'; 이렇게 각 렌더링 방식은 페이지의 데이터 처리 방식과 성능에 따라 다르게 적용될 수 있습니다. pnpm npm i pnpm -g >로 설치 pnpm dlx create-next-app@latest >로 생성한다. pnpm build >로 빌드 pnpm start >페이지열기 프리티어 설정 // 프리티어 pnpm add -D prettier eslint-config-prettier // package.json > scripts "format": "prettier --check --ignore-path .gitignore .", "format:fix": "prettier --write --ignore-path .gitignore ." .eslintrc.json bold 부분 추가! { "extends": ["next/core-web-vitals", "prettier", "plugin:react/recommended", "plugin:react-hooks/recommended", "plugin:react/jsx-runtime"] } //.prettierrc 파일 생성! { "singleQuote": true, "jsxSingleQuote": true, "semi": true, "tabWidth": 2, "trailingComma": "es5" } > 프리티어 자동으로 단축키 -> 쉬프트 + 알트 + F 프리티어 ++++ install $> pnpm add -D @trivago/prettier-plugin-sort-imports .prettierrc 파일 생성! { "singleQuote": true, "jsxSingleQuote": true, "semi": true, "trailingComma": "es5", "plugins": ["@trivago/prettier-plugin-sort-imports"], "importOrder": [ "^next$", "^next/\\w*$", "^next/(.*)$", "^react$", "^react/(.*)$", "^@/lib/(.*)$", "^[./]" ] } 그리고 pnpm format > 실행 eslint pnpm add -D eslint-plugin-react eslint-plugin-react-hooks @next/eslint-plugin-next
[하나은행] Digital hana 路
· 2024-10-07
React
리액트 ## 프론트 면접 use디바운스,debounce가 너무 중요하다!! 훅들에 대해서 프론트엔드 기술 면접을 물어본다!! 어떻게 동작이 되는지 알아두기 아침정리 useState useState는 컴포넌트의 상태(state)를 관리하는 훅입니다. 상태는 컴포넌트의 값이나 UI를 동적으로 변경할 때 사용됩니다. import React, { useState } from 'react'; function Counter() { // count는 상태 값, setCount는 상태를 업데이트하는 함수 const [count, setCount] = useState(0); return ( <div> <p>Count: {count}</p> <button onClick={() => setCount(count + 1)}>Increment</button> </div> ); } useState(0)은 count의 초기값을 0으로 설정하고, setCount 함수로 count 값을 변경할 수 있습니다. 버튼을 클릭하면 상태가 증가하고, 컴포넌트가 다시 렌더링됩니다. useRef useRef는 DOM 요소에 접근하거나 렌더링 간 유지해야 하는 값을 저장하는 데 사용됩니다. 렌더링과 상관없이 유지되는 값을 저장하며, 렌더링을 트리거하지 않습니다. import React, { useRef } from 'react'; function TextInputWithFocusButton() { const inputEl = useRef(null); const onFocusClick = () => { // input 요소에 직접 접근해 포커스를 줌 inputEl.current.focus(); }; return ( <div> <input ref={inputEl} type="text" /> <button onClick={onFocusClick}>Focus the input</button> </div> ); } useRef를 통해 inputEl.current로 DOM 요소에 접근할 수 있습니다. onFocusClick을 통해 버튼을 클릭하면 입력 필드에 포커스를 줍니다. useContext useContext는 React의 Context API에서 전역 상태나 데이터를 소비할 때 사용합니다. Context를 통해 컴포넌트 트리에서 값을 props로 전달하지 않고 사용할 수 있습니다. import React, { createContext, useContext, useState } from 'react'; const UserContext = createContext(null); function App() { const [user, setUser] = useState({ name: 'John', age: 30 }); return ( <UserContext.Provider value={user}> <Profile /> </UserContext.Provider> ); } function Profile() { const user = useContext(UserContext); return <div>{`Hello, ${user.name}!`}</div>; } UserContext.Provider에서 user 데이터를 하위 컴포넌트에 전달하고, Profile 컴포넌트에서 useContext(UserContext)를 사용해 user 값을 가져옵니다. useEffect useEffect는 컴포넌트가 렌더링되거나 업데이트될 때 부수 효과를 처리하기 위해 사용됩니다. 예를 들어, 데이터 패칭, 이벤트 리스너 등록/제거, 타이머 설정 등을 처리할 때 유용합니다. import React, { useState, useEffect } from 'react'; function Timer() { const [count, setCount] = useState(0); useEffect(() => { const timer = setInterval(() => { setCount((prevCount) => prevCount + 1); }, 1000); // 컴포넌트가 언마운트될 때 타이머를 정리함 return () => clearInterval(timer); }, []); return <div>{count}</div>; } useEffect는 컴포넌트가 렌더링될 때 타이머를 시작하고, 컴포넌트가 언마운트되면 타이머를 정리합니다. 타이머는 1초마다 count 값을 증가시킵니다. useLayoutEffect useLayoutEffect는 DOM이 업데이트된 후 바로 실행되며, 화면에 그려지기 전에 동기적으로 실행됩니다. DOM 조작이 필요할 때 사용됩니다. import React, { useState, useLayoutEffect, useRef } from 'react'; function LayoutEffectExample() { const [size, setSize] = useState(0); const divRef = useRef(null); useLayoutEffect(() => { // div의 너비를 가져와서 상태로 저장 if (divRef.current) { setSize(divRef.current.offsetWidth); } }); return ( <div> <div ref={divRef} style={{ width: '100px', height: '100px', backgroundColor: 'lightblue' }} /> <p>Div width: {size}px</p> </div> ); } useLayoutEffect는 DOM이 업데이트된 후 동기적으로 실행되며, div의 크기를 계산해 size 상태로 저장합니다. useCallback useCallback은 특정 함수의 재생성을 방지하는 훅입니다. 컴포넌트가 렌더링될 때마다 불필요하게 함수가 다시 생성되는 것을 막고, 성능 최적화에 도움을 줍니다. import React, { useState, useCallback } from 'react'; function Counter() { const [count, setCount] = useState(0); const increment = useCallback(() => { setCount((prevCount) => prevCount + 1); }, []); return ( <div> <p>Count: {count}</p> <button onClick={increment}>Increment</button> </div> ); } useCallback을 사용해 increment 함수가 재생성되지 않도록 설정했습니다. 이는 컴포넌트가 불필요하게 렌더링되지 않도록 방지합니다. useMemo useMemo는 특정 값의 재계산을 방지하고, 메모이제이션을 통해 성능 최적화를 수행합니다. 컴포넌트가 렌더링될 때마다 값이 다시 계산되지 않도록 제어할 수 있습니다. import React, { useState, useMemo } from 'react'; function ExpensiveCalculation(num) { console.log('Expensive calculation...'); return num * 2; } function Calculator() { const [number, setNumber] = useState(0); const [text, setText] = useState(''); const doubledNumber = useMemo(() => ExpensiveCalculation(number), [number]); return ( <div> <input value={text} onChange={(e) => setText(e.target.value)} placeholder="Type something" /> <button onClick={() => setNumber(number + 1)}>Increment Number</button> <p>Doubled Number: {doubledNumber}</p> </div> ); } useMemo를 사용해 ExpensiveCalculation 함수가 number 값이 변경될 때만 다시 실행되도록 합니다. 이를 통해 불필요한 재계산을 방지합니다. 테일윈드 $ yarn add tailwind-merge https://www.npmjs.com/package/tailwind-merge clsx yarn add clsx 라우팅 yarn add react-router-dom yarn add -D @types/react-router-dom
[하나은행] Digital hana 路
· 2024-09-30
React
리액트 깃허브로 페이지 배포(간단히) master 브런치로 이동하여서(당연히 dev꺼를 add, 커밋해두고!) merge를 해서 dev브런치꺼를 합쳐둔다!! 그리고 설치 공통 (배포 전) $> yarn add gh-pages -D # npm i gh-pages -D package.json > script > "deploy": "gh-pages -d dist", 추가! 추가설정 Deploying to https://<USERNAME>.github.io/<REPO> # 1. vite.config.ts에서 base 설정 export default defineConfig({ plugins: [react()], base: '/<REPO>/', // ex. base: '/hana4/', }); # 1. main.tsx > BrowserRouter →→ HashRouter // github은 try_files를 줄 수 없으므로 #으로 링크! # 2. add & commit into master(main) branch # 3. run build & deploy $> yarn build # npm run build vite build $> yarn deploy # https://indiflex.github.io/hana4 // 브라우저 cache면 쿠키 제거! https://<github-id>.github.io/<repository> Cf. git push -f git@github.com:indiflex/hana4.git main:gh-pages 깃허브 해당 리파지토리 폴더에 들어가서 세팅-> Pages -> 브런치 선택(gh-pages) ->완료 stroybook/스토리북 storybook.js.org $> npx storybook@latest init $> yarn storybook
[하나은행] Digital hana 路
· 2024-09-30
React
리액트 Hook, 훅 상태관리 Hooks useState useContext (createContext) useReducer 시점 Hooks useLayoutEffect (render후, sync) useEffect (paint후, async) 메모화 Hooks useMemo useCallback memo 그 외 Hooks useRef, useImperativeHandle useDebugValue, useId state const [상태변수, 세터] = useState(초깃값/초기화함수);로 초기화를 해서 바꾸어주어야한다
[하나은행] Digital hana 路
· 2024-09-23
React
리액트 설치 <git bash> 필수 설치 - node/npm: https://nodejs.org (by NVM / Volta) $> nvm install --lts $> nvm use v20.10.0 $> nvm alias default v20.10.0 - npx: $> npx -v # 없다면.. - $> npm i npx -g - vscode: https://code.visualstudio.com/download 기타 - React DevTools # 리액트 개발자 도구 - yarn: npm i yarn -g # brew install yarn - vite: https://vitejs-kr.github.io/ - git: https://git-scm.com/download 설정 <git bash> vite >= node v14.18 or LTS $> yarn create vite <rbvite> # yarn create vite rbvite --template react-ts # npm init vite@latest rbvite # in rb $> cd rbvite $> yarn # npm i $> yarn build # npm run build $> yarn dev //으로 실행 확장팩 <vscode> prettier ESLint 초기 설정 <git bash> $> yarn add -D eslint-plugin-react $> yarn add -D eslint-plugin-jsx-a11y # 접근성 <.eslintrc.cjs> .eslintrc.cjs bold 부분 수정! module.exports = { env: { browser: true, es2021: true, node: true }, extends: [ 'eslint:recommended', 'plugin:react/recommended', 'plugin:react/jsx-runtime', 'plugin:jsx-a11y/recommended', ], overrides: [], parserOptions: { ecmaFeatures: { jsx: true }, ecmaVersion: 'latest', sourceType: 'module', }, plugins: ['react-refresh', 'react-hooks', 'jsx-a11y'], rules: { 'react/react-in-jsx-scope': 'off', 'react/jsx-uses-react': 'off', 'react-hooks/rules-of-hooks': 'error', 'react-hooks/exhaustive-deps': 'warn', 'react/prop-types': 'off', 'react/no-array-index-key': 'error', }, settings: { react: { version: 'detect' }, // for react version warnning }, }; <git bash> install $> yarn add -D prettier eslint-config-prettier eslint-plugin-prettier $> yarn prettier # package.json > script > "prettier": "prettier --write .", .eslintrc.cjs bold 부분 추가! export default { env: { browser: true, es2021: true, }, extends: [ …, 'plugin:prettier/recommended', ], overrides: [], parserOptions: { … }, plugins: ['react', 'react-hooks', 'jsx-a11y', 'prettier']], rules: { …, 'prettier/prettier': 'error', quotes: ['error', 'single', { allowTemplateLiterals: true }], }, … }; /// .prettierrc 파일 생성! { "singleQuote": true, "jsxSingleQuote": true, "semi": true, "trailingComma": "es5" } // prettier 기타 "endOfLine": "auto", "tabWidth": 2, "useTabs": false, "printWidth": 100 <eslint.config.js> import js from '@eslint/… import react from 'eslint-plugin-react'; import prettier from 'eslint-plugin-prettier'; import eslintConfigPrettier from 'eslint-config-prettier'; export default tseslint.config( … plugins: { 'react-hooks': reactHooks, 'react-refresh': reactRefresh, react, prettier, }, settings: { react: { version: '18.3' }, // React version for react plugin }, rules: { ...js.configs.recommended.rules, // ESLint rules ...react.configs.recommended.rules, // React rules ...react.configs['jsx-runtime'].rules, // JSX rules ...reactHooks.configs.recommended.rules, 'react-refresh/only-export-components': [ 'warn', { allowConstantExport: true }, ], 'prettier/prettier': 'error', }, }, eslintConfigPrettier ); <eslint.config.js> import jsxA11y from 'eslint-plugin-jsx-a11y'; export default tseslint.config( { ignores: ['dist'] }, { extends: [js.configs.recommended, ...tseslint.configs.recommended], … plugins: { 'react-hooks': reactHooks, 'react-refresh': reactRefresh, react, prettier, 'jsx-a11y': jsxA11y, }, settings: { react: { version: '18.3' }, }, rules: { ... ...reactHooks.configs.recommended.rules, 'react-refresh/only-export-components': [ 'warn', { allowConstantExport: true }, ], 'prettier/prettier': 'error', 'jsx-a11y/alt-text': 'error', }, }, eslintConfigPrettier );
[하나은행] Digital hana 路
· 2024-09-20
React
리액트 카카오 프론트코테 구현문제 ReactDOM.render( // 기존 렌더링 방식(sync) React.createElement('h1', null, 'A'), document.getElementById('root') ); const root = ReactDOM.createRoot( // concur document.getElementById('root') ); const element = <h1>Hello, world</h1>; root.render(element); 이 코드는 React 17까지 사용되던 동기식(Synchronous) 렌더링 방식을 사용합니다. ReactDOM.render() 메소드는 DOM에 직접 렌더링을 수행하며, React 요소를 document.getElementById(‘root’) 위치에 렌더링합니다. 이 방식에서는 UI 업데이트가 동기적으로 처리되므로, 매우 큰 작업이 있을 때는 브라우저가 잠시 멈출 수 있습니다. 컴포넌트 //~components/Hello.tsx const Title = ({text, name}:{text:string, name:string}) => <h3>{text}aaaaaaaaaaaaaaaaaa{name}aaaaaaaaaaaaaaaaaaa</h3> //위의 화살표 함수 export default function Hello(){ return <> <Title text = "kkkkkkkkkkkkkk" name="jjjaejjjaejae" /> <h1>hhheoolllo</h1> <div>gggg zzz oooooooooooooo</div> <div className="red" style={{color:'blue'}}>gggg zzz oooooooooooooo</div> //style 선언은 {}로 열고 객체로 넣어주기 </> //export default function으로 만들어서 넣기 }
[하나은행] Digital hana 路
· 2024-09-19
TypeScript
타입스크립트 ##
[하나은행] Digital hana 路
· 2024-09-12
TypeScript
타입스크립트 ##
[하나은행] Digital hana 路
· 2024-09-11
TypeScript
타입스크립트 함수타입 // Call Signature: (a:number, b:number) => number function add(a : number, b: number) { return a + b; } add(1); //Error : Expected 2 arguments, but got 1. add(1, 2); // Ok add(1, 2, 3); //Error : Expected 2 arguments, but got 3. 타입스크립트는 함수에 선언된 모든 매개변수가 필수라고 가정한다! const introduce = (name:string, height?:number) => { //?는 옵셔널파라미터 있어도되고 없어도 되고 console.log(`이름 : ${name}`); console.log(`키 : ${height + 10}`) //Error : 'height' is possibly 'undefined'. } introduce("김현준"); // OK introduce("김현준", undefined); // OK introduce("김현준", 170); // OK 함수 호출에 선택적 매개변수를 인수로 제공할 필요 X 선택적 매개변수에는 항상 | undefined 가 유니언타입으로 추가 되어있기 때문! 선택적 매개변수는 끝에 위치해야함 const introduce2 = (name:string, height : number|undefined ) => { console.log(`이름 : ${name}`); if(typeof height === 'number'){ console.log(`키 : ${height + 10}`) } } introduce2("김현준"); // Error : Expected 2 arguments, but got 1. introduce2("김현준", undefined); // OK introduce2("김현준", 170); // OK 선택적 매개변수는 | undefined를 포함하는 유니언 타입 매개변수와 다름. ?으로 표시된 선택적 매개변수가 아닌 매개변수는 값이 명시적으로 undefined 일지라도 항상 제공되어야 한다. const getSum = (...rest: number[]) =>{ //rest로 여러개의 넘버를 받음(넘버만!) const getSum2 = (a: number,...rest:[number, number]) =>{ //튜플로 rest로 두개의 넘버를 받음 function singSongRecursive(songs : string[], count = 0) : number { return songs.length ? singSongRecursive(songs.slice(1), count + 1) : count; } // 재귀함수에서의 명시적 반환 타입지정 let singer : (song : string) => string; singer = function(song) { // song : string의 타입 return `Singing : ${song.toUpperCase()}!`; // OK } //타입 스크립트는 선언된 타입의 위치에 제공된 함수의 매개변수 타입을 유추할 수 있다! void 반환타입 function logSong(song : string) : void { if(!song){ return; // OK! return undefined; 도 OK! } console.log(`${song}`); return true; // Error! - Type 'boolean' is not assignable to type 'void'. } // ← void를 반환하도록 선언되었으므로 값 반환을 허용하지 않음. // But, 다음과 같이 화살표 함수는 구문 오류 없음! type VoidReturn = () => void; const test2:VoidReturn = () => 11; // OK! test2().toString(); // ? //일부 함수는 어떤 값도 반환하지 않을 수 있음 -> 타입스크립트는 void 키워드를 사용해 반환값이 없는 함수의 타입을 확인할 수 있음 //void는 그냥 반환을 하려해도 타입스크립트는 검사를 안한다 //fuction은 등록을 해야해서 void를 썻는데 return이 있으면 오류뜨고 //화살표함수는 이미 등록이라서 void인데 return이 있어도 ㅇㅋ never 반환타입 never 반환 함수는 (의도적으로) 항상 오류를 발생시키거나 무한 루프를 실행하는 함수 function fail(message : string) : never { throw new Error(`Invariant Failure : ${message}`); // JS는 return undefined; 가 생략 } function workWithUnsafeParam(param : unknown){ if(typeof param !== "string"){ fail(`param should be a string, not ${typeof param}`); } // 여기에서 param의 타입은 string으로 알려짐 param.toUpperCase(); } 함수 오버로드 동일한 이름에 매개 변수만 다른 여러 버전의 함수를 만드는 것 매개변수의 형태가 다양한 여러 케이스에 대응하는 같은 이름을 가진 함수를 만드는 것 // 서로 다른 버전의 함수들(선언부) -> `오버로드 시그니처` function func(a : number): void; function func(a : number, b : number, c : number) : void; // 실제 구현부 -> `구현 시그니처` function func(a:number, b?: number, c?:number) { if(typeof b === 'number' && typeof c === 'number') { console.log(a + b + c); } else { console.log(a * 20); } } func(1); func(1,2,3); this 동일한 이름에 매개 변수만 다른 여러 버전의 함수를 만드는 것 매개변수의 형태가 다양한 여러 케이스에 대응하는 같은 이름을 가진 함수를 만드는 것 function f(cb: (this: void) => number) { return cb(); } // 이 함수 f는 콜백 함수 cb를 매개변수로 받고 있는데, cb는 this를 사용하지 않는 함수여야 한다는 것을 명시하고 있습니다. 이를 위해 cb의 타입으로 (this: void) => number를 지정했는데, 이는 this가 void 타입임을 나타냅니다. 즉, this를 사용하지 않는 함수여야 한다는 뜻입니다. const obj = { id: 1 }; function x(this: typeof obj) { return this.id; } function y() { return 1; } f(x); // Fail f(y); // OK // f(x): // 실패하는 이유는 x 함수가 this로 obj를 필요로 하지만, f 함수는 cb의 this가 void라고 명시했기 때문입니다. 즉, f는 this를 사용하지 않는 함수만 받을 수 있는데, x는 this를 사용하므로 타입 호환이 되지 않습니다. // 오류 메시지에서 설명하듯이, void 타입의 this는 { id: number }와 호환되지 않습니다. // f(y): // 성공하는 이유는 y 함수는 this를 사용하지 않으므로, this: void로 선언된 콜백 함수로 사용할 수 있기 때문입니다. Tip. tsconfig.json 에서 strict: true 가 포함하는 옵션들 { "strict": true, "strictNullChecks": true, "strictFunctionTypes": true, "strictBindCallApply": true, "strictPropertyInitialization": true, "noImplicitThis": true, "alwaysStrict": true, } // noUncheckedIndexedAccess : 해당 index의 값이 undefined일 수 있음을 체크하겠다! 이 옵션을 true로 설정하면 인덱스 시그니처에 'undefined'를 포함시킨다! 결합 concat을 이용한 결합 const nums1 = [1, 2, 3, 4, 5]; const nums2 = [10, 20, 30, 40, 50]; const result1 = nums1.concat(nums2); // 당연히 result1은 number[] const strings1 = ['lim', 'eun', 'ha']; const result2 = result1.concat(strings1);// 에러가 뜬다. concat은 결합할 것의 타입이 같아야함 spread를 이용한 결합 const nums1 = [1, 2, 3, 4, 5]; const nums2 = [10, 20, 30, 40, 50]; const result1 = nums1.concat(nums2); // 당연히 result1은 number[] const strings1 = ['lim', 'eun', 'ha']; const result2 = [...result1, …strings1]; // 둘을 결합한 result2는 ?? (string | number)[] 튜플 고정된 크기의 배열. 각 인덱스에 알려진 특정 타입을 갖는다! 즉) 자리수가 고정이 튜플인것이다. 튜플 타입은 가변 길이의 배열보다 더 구체적이다! 따라서, 배열은 튜플 타입의 변수에 할당할 수 없다. 타입스크립트는 튜플의 길이를 알고있다. 따라서 길이가 다른 튜플은 서로 할당할 수 없다! 인수에 배열 스프레드를 사용한 경우 해당 함수는 나머지 매개변수가 꼭 있어야 한다. 나머지 매개변수가 없다면 배열을 전달할 경우 반드시 튜플만 스프레드하여 전달할 수 있다! /** 함수의 매개변수 튜플 인터페이스 타입스크립트에서 인터페이스(interface)는 객체의 구조를 정의하는 데 사용되는 일종의 계약(Contract)입니다. 인터페이스는 객체가 어떤 속성을 가져야 하는지, 그리고 그 속성들이 어떤 타입이어야 하는지를 명시합니다. interface User { id: number; name: string; age?: number; // 선택적 속성 (optional property) } let user1: User = { id: 1, name: "Alice" }; let user2: User = { id: 2, name: "Bob", age: 30 }; // interface Greet { (name: string): string; } const greetUser: Greet = (name: string) => { return `Hello, ${name}`; }; console.log(greetUser("Alice")); // 출력: Hello, Alice 숫자 인덱스 시그니처(경력자 질문으로 많이 물어본다) 왜 오류가 날까? 넘버가 통과를 못해서? 어떻게 해결을 할까? ###
[하나은행] Digital hana 路
· 2024-09-10
TypeScript
타입스크립트? 타입스크립트의 구성 4가지 프로그래밍 언어: 새로운 구문이 포함된 언어 타입 검사기(TypeChecker): 코드의 모든 구성요소(함수,변수 등)를 이해하고 오류 감별 컴파일러(Pre-Compiler): TS Syntax-tree를 JS Code로 생성 (cf. AltJS) Pre 는 선처리가 된다는 말 언어지원 서비스(IDE): VSCode, SublimeText, Vim 등의 편집기에서 TS 지원 타입스크립트 연습하는 사이트 https://www.typescriptlang.org/play/ Settings의 AST를 check하고, 버전을 v5.1.6으로 하여 AST를 확인하자 타입스크립트는 전역의 i와 함수의 i는 서로 다른 심볼로 같은 변수라도 스코프에 따라서 에러가 날 수도 있고 안날 수도 있다. 타입스크립트 설치하기 $> mkdir ts && cd ts $> npm init -y $> npm install -g typescript ts-node $> tsc -v $> tsc --init $> cat tsconfig.json $> ts-node hello.ts ts파일을 만들고 git bash에 tsc 입력하면 js파일이 생김 그리고 tsc –watch를 git bash에 입력해두면 ts파일을 수정하면 자동으로 js파일도 바뀜 타입스크립트의 타입 //null let value: null = null; //undefined let value: undefined = undefined; //boolean let isDone: boolean = false; //string let name: string = "TypeScript"; let greeting: string = `Hello, ${name}`; //큰따옴표("), 작은따옴표('), 또는 백틱(`)을 사용하여 문자열을 정의할 수 있습니다 //number let count: number = 10; let pi: number = 3.14159; //bigint let largeNumber: bigint = 123456789012345678901234567890n; //symbol let sym1 = Symbol("description"); let sym2 = Symbol("description"); // 서로 다른 Symbol 값 //고유하고 변경 불가능한 값으로, 객체의 속성 키로 사용할 수 있습니다. 타입설정하기 let x: number; x=10; console.log("🚀 x:", x); x='abc'; console.log("🚀 x:", x); 로 하면 x는 number로 되어있기에 abc에서 오류뜸 따라서 let x: number sring;으로 해줌 > 유니언(union, (파이프)): 값에 허용되는 타입을 두 개 이상의 가능한 타입으로 확장하는 것 초기값이 없는 변수 타입 undefined로 주자 (any로 주지 말자) 할당 되기 전, 속성 중 하나에 접근 하려고 하는 것처럼 변수를 사용하려고 하면 에러 발생 undefined 유니온 타입일 때 접근 가능한 이유는 undefined 할당 가능성을 미리 알렸기 때문 JS에서는 값을 할당하지 않는다면 초기화 값인 undefined를 참조, TS에선 이를 미리 타입으로 설정해야 참조 가능 => 결론: undefined 가능성을 미리 알리지 않았기 때문에 할당 없이 접근하려고 했을 때 에러 발생 type 정의 타입스크립트에서 type 키워드를 사용하여 객체의 타입을 정의하는 방법은 매우 유용합니다. 이를 통해 객체 구조를 미리 정의하고, 해당 구조를 여러 곳에서 재사용할 수 있습니다. type 키워드를 사용하여 특정 타입의 형식을 정의할 수 있으며, 인터페이스와 유사하게 동작합니다. type User = { id:number; name:string; age:number; address:string; } 스크립트 파일의 선언 스코프 타입스크립트에서 “스크립트 파일”은 전역 스코프에서 실행됩니다. 즉, 파일 간에 명시적인 import나 export가 없으면, 모든 선언(변수, 함수 등)이 전역 스코프에 존재하게 됩니다. 따라서 한 스크립트 파일에서 선언된 변수가 다른 스크립트 파일과 충돌할 수 있습니다. 스크립트 파일의 특징: 전역 스코프에 존재. 다른 스크립트 파일에서도 동일한 이름의 변수를 선언할 수 없음. 서로 다른 파일에 동일한 변수를 선언하면 충돌이 발생. // a.ts (스크립트 파일로 간주됨 - import/export 없음) const shared = 'Cher'; // b.ts (또 다른 스크립트 파일) const shared = 'Cher'; // 오류 발생: 이미 전역에 같은 이름의 변수가 존재 이 경우 타입스크립트는 shared 변수가 전역 스코프에서 중복 선언된 것으로 판단해 오류를 발생시킵니다. ECMAScript 모듈의 선언 스코프 모듈 시스템을 사용할 때는 import와 export를 통해 각 파일이 모듈 단위로 동작하게 됩니다. 모듈 파일은 각각 자체적인 스코프를 가지며, 파일 간의 변수 충돌이 발생하지 않습니다. 즉, 파일 간의 이름 충돌은 피할 수 있습니다. 하지만 동일한 모듈 내에서 선언이 충돌하면 오류가 발생합니다. 모듈 파일의 특징: 파일이 모듈로 간주되면, 각 모듈은 자체적인 스코프를 가짐. 같은 이름의 변수를 여러 파일에서 선언해도 충돌이 발생하지 않음. 하지만 같은 파일 내에서 import된 변수와 동일한 이름의 변수를 다시 선언하면 오류가 발생. // a.ts (모듈 파일) export const shared = 'Cher'; // b.ts (모듈 파일) export const shared = 'Cher'; // c.ts (모듈 파일) import { shared } from './a'; // 'shared'는 'a.ts'에서 import됨 export const shared = 'Cher'; // 오류: 동일한 이름의 변수를 동일 파일에서 다시 선언할 수 없음 스크립트 파일: 전역 스코프를 공유하기 때문에 파일 간 변수 충돌이 발생할 수 있습니다. 모듈 파일: 파일 간에 독립된 스코프를 가지지만, 같은 파일 내에서 동일한 이름의 변수를 선언하면 오류가 발생합니다. 리터럴 타입 리터럴 타입(Literal Types)은 타입스크립트에서 더 구체적인 값으로 변수를 제한할 수 있는 기능입니다. 원시 타입(숫자, 문자열 등)의 특정 값 자체를 타입으로 사용하여, 특정 값만을 허용하는 방식입니다. 이를 통해 타입 안전성을 높이고 코드에서 명확한 제약을 설정할 수 있습니다. let direction: 'left' | 'right' | 'up' | 'down'; direction = 'left'; // 가능 direction = 'up'; // 가능 direction = 'forward'; // 오류: 'forward'는 허용되지 않음 유니언 타입(|)과 인터섹션 타입(&) 유니언 타입은 두 개 이상의 타입 중 하나를 가질 수 있도록 허용합니다. 즉, 값이 여러 타입 중 하나를 선택할 수 있는 상황에서 사용됩니다. type A = string | number; let value: A; value = "Hello"; // 문자열 할당 가능 value = 123; // 숫자 할당 가능 value = true; // 오류: boolean은 허용되지 않음 인터섹션 타입은 두 개 이상의 타입을 모두 만족해야 합니다. 즉, 타입들이 합쳐져서 모든 타입의 속성이나 메서드를 모두 갖는 하나의 타입이 됩니다. ```typescript type B = { name: string } & { age: number }; let person: B; person = { name: “John”, age: 30 }; // 가능 person = { name: “John” }; // 오류: age 속성이 없음 person = { age: 30 }; // 오류: name 속성이 없음 --- ### strictNullChecks 엄격한 null 검사 활성화 / 비활성화: null 혹은 undefined 값을 참조/할당 했을 때 타입 에러 발생 여부 ⇒ 10억 달러의 실수! (NullPointerException) ⇒ `strict: true` > 폴더이름config.json의 `"strictNullChecks": true`로 해주자!!!! 엄격한 null 검사 활성화: 다른 타입이 필요한 위치에서 null 혹은 undefined 값을 참조/할당 하는 것을 방지한다! (즉, 활성화해야만 null 및 undefined에 대해한 오류로 부터 안전해진다!) --- ### 할당 ```typescript let xuser: {id: number, name: string}; xuser = {id: 1, name: 'xx'}; // OK xuser = {id: 1}; // Error: name 속성이 없습니다 xuser = {id: 1, name: 'xx', age: 30}; // Error: {id, name, age}는 {id, name}에 할당할 수 없습니다. 첫 번째 할당에서는 {id: number, name: string} 타입과 정확히 일치하므로 문제가 없습니다. 두 번째 할당은 name 속성이 누락되어 오류가 발생합니다. 세 번째 할당은 추가 속성(age)이 포함되어 있어, 타입스크립트는 예상된 타입에 불필요한 속성이 있다고 판단해 오류를 발생시킵니다. 이는 신선함 검사(freshness check)에 의해 발생한 것입니다. hong = {id: 1, name: 'Hong', addr: 'Pusan'} as TUser; // OK as TUser를 사용하면 타입스크립트는 신선함 검사를 비활성화합니다. 이 경우, 타입스크립트는 이 객체가 TUser라고 간주하고, 추가된 속성 addr을 무시합니다. 즉, 타입 단언(assertion)을 사용해 추가된 속성 검사 오류를 무시할 수 있습니다. CoVariance & ContraVariance // strictFunctionTypes = true function f(cb: (input: string | number)=> number) {return cb(1);} function f2(input: string | number | boolean) {return 1;} function f3(input: string | number) {return 1;} function f4(input: string) {return 1;} f(f2); f(f3); f(f4); f 함수는 매개변수로 (input: string | number) => number 타입의 콜백 함수 cb를 받습니다. 즉, cb는 string 또는 number 타입의 입력을 받을 수 있어야 합니다. f2는 string | number | boolean 타입의 매개변수를 받을 수 있습니다. 문제: f2는 boolean 타입도 받을 수 있는 콜백 함수이지만, f는 boolean을 허용하지 않습니다. 타입스크립트는 매개변수의 반공변성(contravariance) 때문에 더 넓은 타입(즉, boolean까지 포함하는 f2)을 더 좁은 타입(string | number만 허용하는 f)에 할당하는 것을 허용하지 않습니다. 요약: f2는 boolean 타입까지 허용하므로, f에 사용할 수 없습니다. 그러나 TypeScript는 실제로는 함수 매개변수의 반공변성을 완전히 엄격하게 적용하지 않고, 어떤 상황에서는 더 넓은 타입을 허용합니다. 이 경우, 매개변수 타입이 넓은 함수인 f2를 매개변수 타입이 좁은 함수인 f의 콜백으로 사용해도 오류가 발생하지 않습니다. 이런 허용은 TypeScript가 실무에서 좀 더 유연하게 사용될 수 있도록 일부러 설계된 부분입니다. 즉, TypeScript는 완전한 반공변성을 강제하지 않고, 보다 유연하게 함수 타입을 비교하는 경우가 있습니다. f3는 string | number 타입을 매개변수로 받으며, 이는 f가 요구하는 타입과 일치합니다. 문제 없음: f3의 시그니처는 f의 요구 사항과 정확히 일치하므로, f(f3)는 정상적으로 작동합니다. f4는 string만 매개변수로 받습니다. 문제: f4는 number 타입의 입력을 처리하지 못합니다. 하지만 f는 콜백 함수가 string | number 타입의 입력을 처리할 수 있어야 한다고 요구합니다. f는 number를 전달할 수 있지만, f4는 number를 허용하지 않기 때문에 오류가 발생합니다. 요약: f4는 number를 처리할 수 없기 때문에 f(f4)는 허용되지 않습니다. 0910 아침 정리 유니온 A B는 A 또는 B가 할당 가능하다는 뜻 인터섹션 A&B는 A와B가 합쳐진 것
[하나은행] Digital hana 路
· 2024-09-09
호이스팅의 원리
호이스팅이란? Fill the image path to the ‘thumbnail’ attribute, if you want a main image to be displayed on the post header image. The rest content is just meaningless dummy text. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Dㄴuis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
[하나은행] Digital hana 路
· 2024-09-07
<
>
Touch background to close