JavaScript๋ก ๊ท๋ชจ๊ฐ ์ปค์ง๋ ํ๋ก์ ํธ๋ฅผ ์์ ํ๋ค ๋ณด๋ฉด ์ด๋ ์๊ฐ ์ด๋ฐ ์ํฉ์ด ์จ๋ค.
function calculateTotal(items) {
return items.reduce((sum, item) => sum + item.pricee, 0); // ์คํ์ธ๋ฐ ์ค๋ฅ ์์
}pricee๋ผ๋ ์คํ๊ฐ ์์ง๋ง JavaScript๋ ์๋ฌด ๊ฒฝ๊ณ ๋ ์ฃผ์ง ์๋๋ค. ์คํํ๋ฉด NaN์ด ๋์ค๊ณ , ๊ทธ๋์ผ ๋๋ฒ๊น
์ ์์ํ๋ค. TypeScript๋ ์ด๋ฐ ๋ฌธ์ ๋ฅผ ์ฝ๋๋ฅผ ์์ฑํ๋ ์๊ฐ ์ก์์ค๋ค.
์ TypeScript์ธ๊ฐ
JavaScript๊ฐ ๋์น๋ ์ค๋ฅ๋ค
// โ ๋ฐํ์์ ํฐ์ง๋ JavaScript ์ฝ๋๋ค
// 1. ์กด์ฌํ์ง ์๋ ์์ฑ ์ ๊ทผ
const user = { name: 'Alice', age: 25 };
console.log(user.email.toLowerCase()); // TypeError: Cannot read properties of undefined
// 2. ์๋ชป๋ ํ์
์ฐ์ฐ
function double(n) {
return n * 2;
}
double('3'); // "33" โ ๋ฌธ์์ด์ด ๋ค์ด์๋๋ฐ ์ค๋ฅ ์์
// 3. ์คํ
const CONFIG = { apiUrl: 'https://api.example.com' };
fetch(CONFIG.apiURl); // undefined โ ์คํ์ธ๋ฐ ์กฐ์ฉํ ์คํจ์ด ๋ชจ๋ ์ค๋ฅ๋ ๋ฐํ์์ ์ฌ์ฉ์๊ฐ ์ง์ ๋ง์ฃผ์น๊ฒ ๋๋ค.
TypeScript๋ฅผ ์ฐ๋ฉด ๊ฐ์ ์ฝ๋๊ฐ ์ปดํ์ผ ํ์์ ๋ฐ๋ก ์ค๋ฅ๋ก ํ์๋๋ค:
// โ
TypeScript๊ฐ ๋ฏธ๋ฆฌ ์ก์์ฃผ๋ ์ค๋ฅ๋ค
const user: { name: string; age: number } = { name: 'Alice', age: 25 };
console.log(user.email.toLowerCase()); // ์ค๋ฅ: 'email' ์์ฑ์ด ์์
function double(n: number): number {
return n * 2;
}
double('3'); // ์ค๋ฅ: 'string'์ 'number' ๋งค๊ฐ๋ณ์์ ํ ๋นํ ์ ์์TypeScript ์ฑํ ํํฉ
- Stack Overflow ๊ฐ๋ฐ์ ์ค๋ฌธ(2024)์์ TypeScript๋ ๊ฐ์ฅ ์ฌ๋๋ฐ๋ ์ธ์ด 4์
- Angular๋ TypeScript ๊ธฐ๋ณธ, React/Vue๋ TypeScript First ๋ฐฉํฅ์ผ๋ก ์ ํ ์ค
- Microsoft, Google, Airbnb, Slack ๋ฑ ๋ํ ํ๋ก์ ํธ ๋๋ถ๋ถ TypeScript ์ฌ์ฉ
TypeScript ์ค์น ๋ฐ ์์
์์ TypeScript ํ๋ก์ ํธ
# TypeScript ์ปดํ์ผ๋ฌ ์ค์น
npm install -g typescript
# ๋ฒ์ ํ์ธ
tsc --version
# ํ๋ก์ ํธ ์ด๊ธฐํ (tsconfig.json ์์ฑ)
tsc --init
# ์ปดํ์ผ
tsc index.ts
# ๊ฐ์ ๋ชจ๋ (ํ์ผ ๋ณ๊ฒฝ ์ ์๋ ์ปดํ์ผ)
tsc --watchtsconfig.json ์ฃผ์ ์ต์
{
"compilerOptions": {
"target": "ES2020", // ์ปดํ์ผ ๊ฒฐ๊ณผ๋ฌผ์ JavaScript ๋ฒ์
"module": "commonjs", // ๋ชจ๋ ์์คํ
(commonjs / ESNext)
"lib": ["ES2020", "DOM"], // ์ฌ์ฉํ ๋ด์ฅ ํ์
๋ผ์ด๋ธ๋ฌ๋ฆฌ
"outDir": "./dist", // ์ปดํ์ผ ๊ฒฐ๊ณผ๋ฌผ ์ ์ฅ ์์น
"rootDir": "./src", // TypeScript ์์ค ํ์ผ ์์น
"strict": true, // ์๊ฒฉ ๋ชจ๋ (๊ฐ๋ ฅ ๊ถ์ฅ!)
"esModuleInterop": true, // CommonJS ๋ชจ๋ import ํธ์์ฑ
"skipLibCheck": true, // node_modules ํ์
๊ฒ์ฌ ์๋ต
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
"strict": true๋ ๋ฐ๋์ ์ผ๋์.strictNullChecks,noImplicitAny๋ฑ ํต์ฌ ์ต์ ๋ค์ด ๋ชจ๋ ํ์ฑํ๋๋ค.
Vite + React + TypeScript ์์
# Vite๋ก React + TypeScript ํ๋ก์ ํธ ์์ฑ
npm create vite@latest my-app -- --template react-ts
cd my-app
npm install
npm run dev๊ธฐ๋ณธ ํ์ ์์ ์ ๋ฆฌ
์์ ํ์
// ๊ธฐ๋ณธ ์์ ํ์
const name: string = 'Alice';
const age: number = 25;
const isActive: boolean = true;
// null๊ณผ undefined
let value: null = null;
let data: undefined = undefined;
// symbol
const id: symbol = Symbol('id');
// bigint
const bigNum: bigint = 9007199254740991n;๋ฐฐ์ด๊ณผ ํํ
// ๋ฐฐ์ด โ ๋ ๊ฐ์ง ํ๊ธฐ๋ฒ
const numbers: number[] = [1, 2, 3];
const strings: Array<string> = ['a', 'b', 'c'];
// ์ฝ๊ธฐ ์ ์ฉ ๋ฐฐ์ด
const readOnly: readonly number[] = [1, 2, 3];
// readOnly.push(4); // ์ค๋ฅ!
// ํํ โ ๊ฐ ์์น์ ํ์
์ด ๊ณ ์ ๋จ
const point: [number, number] = [10, 20];
const entry: [string, number] = ['Alice', 25];
// named tuple (TypeScript 4.0+)
const namedPoint: [x: number, y: number] = [10, 20];any, unknown, never, void ๋น๊ต
| ํ์ | ์๋ฏธ | ํ์ ์ฒดํฌ | ์ฌ์ฉ ์์ |
|---|---|---|---|
any |
๋ชจ๋ ํ์ ํ์ฉ, ํ์ ์ฒดํฌ ์์ | โ | ๋ง์ด๊ทธ๋ ์ด์ ์ด๊ธฐ, ์ด์ฉ ์ ์์ ๋๋ง |
unknown |
๋ชจ๋ ํ์ ํ์ฉ, ์ฌ์ฉ ์ ํ์ ์ฒดํฌ ํ์ | โ | API ์๋ต ๋ฑ ํ์ ๋ถ๋ช ํํ ๋ |
never |
์ ๋ ๋ฐ์ํ์ง ์๋ ๊ฐ | โ | ํจ์๊ฐ ํญ์ throw, ๋ฌดํ ๋ฃจํ |
void |
๋ฐํ๊ฐ ์์ | โ | ๋ฐํ๊ฐ์ด ์๋ ํจ์ |
// any โ ํผํ๋ ๊ฒ ์ข๋ค
let anything: any = 42;
anything = 'string'; // OK
anything.foo.bar.baz; // OK (๋ฐํ์ ์ค๋ฅ ์ํ!)
// unknown โ any๋ณด๋ค ์์
let value: unknown = 42;
value.toFixed(2); // ์ค๋ฅ: ํ์
์ฒดํฌ ์์ด ์ฌ์ฉ ๋ถ๊ฐ
if (typeof value === 'number') {
value.toFixed(2); // OK: ํ์
๊ฐ๋ ํ ์ฌ์ฉ
}
// never โ ๋๋ฌ ๋ถ๊ฐ๋ฅํ ์ฝ๋
function throwError(msg: string): never {
throw new Error(msg);
// ์ฌ๊ธฐ ์ดํ ์ฝ๋๋ never ํ์
}
// void โ ๋ฐํ๊ฐ ์๋ ํจ์
function logMessage(msg: string): void {
console.log(msg);
// return 42; // ์ค๋ฅ
}ํ์ ์ถ๋ก (Type Inference)
๋ชจ๋ ๋ณ์์ ํ์ ์ ๋ช ์ํ ํ์๋ ์๋ค. TypeScript๋ ๋๋ถ๋ถ์ ๊ฒฝ์ฐ ํ์ ์ ์์์ ์ถ๋ก ํ๋ค:
// TypeScript๊ฐ ํ์
์ ์๋์ผ๋ก ์ถ๋ก
const name = 'Alice'; // string์ผ๋ก ์ถ๋ก
const age = 25; // number๋ก ์ถ๋ก
const arr = [1, 2, 3]; // number[]๋ก ์ถ๋ก
// ํจ์ ๋ฐํ ํ์
๋ ์ถ๋ก
function add(a: number, b: number) {
return a + b; // ๋ฐํ ํ์
: number (์ถ๋ก ๋จ)
}
// ๋ณต์กํ ๊ฒฝ์ฐ์ ๋ช
์ํ๋ ๊ฒ ์ข์
function getUser(id: number): User {
// ๋ช
์์ ์ผ๋ก ์ฐ๋ฉด ์๋๊ฐ ๋ช
ํํ๊ณ ์ค๋ฅ๋ ๋นจ๋ฆฌ ๋ฐ๊ฒฌ
}์ธํฐํ์ด์ค vs ํ์ ๋ณ์นญ
TypeScript์์ ๊ฐ์ฒด ํ์ ์ ์ ์ํ๋ ๋ฐฉ๋ฒ์ ๋ ๊ฐ์ง๋ค.
interface
interface User {
id: number;
name: string;
email?: string; // optional (์์ด๋ ๋๊ณ ์์ด๋ ๋จ)
readonly createdAt: Date; // ํ ๋ฒ ์ค์ ํ๋ฉด ๋ณ๊ฒฝ ๋ถ๊ฐ
}
// ์ธํฐํ์ด์ค ํ์ฅ
interface Admin extends User {
role: 'admin' | 'superadmin';
permissions: string[];
}
// ์ ์ธ ๋ณํฉ (๊ฐ์ ์ด๋ฆ์ผ๋ก ์ฌ๋ฌ ๋ฒ ์ ์ธํ๋ฉด ํฉ์ณ์ง)
interface Window {
myCustomProp: string; // ๋ธ๋ผ์ฐ์ ์ ์ญ ๊ฐ์ฒด ํ์ฅ ๊ฐ๋ฅ
}type alias
type User = {
id: number;
name: string;
email?: string;
};
// Union ํ์
type ID = string | number;
type Status = 'active' | 'inactive' | 'pending';
// Intersection ํ์
(๋ชจ๋ ํ์
์ ์์ฑ์ ํฉ์นจ)
type AdminUser = User & { role: string; permissions: string[] };
// ํจ์ ํ์
type Handler = (event: MouseEvent) => void;์ธ์ interface vs type?
interface |
type |
|
|---|---|---|
| ๊ฐ์ฒด ํ์ ์ ์ | โ | โ |
| Union / Intersection | โ | โ |
| ์ ์ธ ๋ณํฉ | โ | โ |
| extends | โ | &๋ก ๊ฐ๋ฅ |
| ์์ ํ์ ๋ณ์นญ | โ | โ |
์ค๋ฌด ๊ฐ์ด๋๋ผ์ธ:
- interface: ๊ฐ์ฒด(ํด๋์ค, API ์๋ต ๋ฑ) ํ์ ์ ์ โ ํ์ฅ ๊ฐ๋ฅ์ฑ์ด ์์ ๋
- type: Union, Intersection, ํจ์ ํ์ , ์ ํธ๋ฆฌํฐ ํ์ ์กฐํฉ โ ์ ์ฐํ ํ์ ์ด ํ์ํ ๋
- ํ์ด ์๋ค๋ฉด ์ผ๊ด์ฑ์ด ๊ฐ์ฅ ์ค์. ํ๋๋ก ํต์ผํด์ ์ฐ๋ ๊ฒ ๋ซ๋ค.
ํจ์ ํ์
// ๊ธฐ๋ณธ ํจ์ ํ์
function add(a: number, b: number): number {
return a + b;
}
// ํ์ดํ ํจ์
const multiply = (a: number, b: number): number => a * b;
// ์ ํ์ ๋งค๊ฐ๋ณ์ (?)
function greet(name: string, greeting?: string): string {
return `${greeting ?? 'Hello'}, ${name}!`;
}
// ๊ธฐ๋ณธ๊ฐ
function greet(name: string, greeting: string = 'Hello'): string {
return `${greeting}, ${name}!`;
}
// ๋๋จธ์ง ๋งค๊ฐ๋ณ์
function sum(...numbers: number[]): number {
return numbers.reduce((acc, n) => acc + n, 0);
}
// ํจ์ ์ค๋ฒ๋ก๋ฉ
function format(value: string): string;
function format(value: number): string;
function format(value: string | number): string {
if (typeof value === 'string') return value.toUpperCase();
return value.toFixed(2);
}์ ๋ค๋ฆญ (Generics)
์ ๋ค๋ฆญ์ ํ์ ์ ๋ณ์์ฒ๋ผ ๋ค๋ฃจ๋ ๊ธฐ๋ฅ์ด๋ค. "์ด๋ค ํ์ ์ด๋ ๋์ํ๋, ํ์ ์์ ์ฑ์ ์ ์งํ๊ฒ ๋ค"๋ ๋ป์ด๋ค.
// ์ ๋ค๋ฆญ ์์ด โ ํ์
์ ๋ณด ์์ค
function identity(value: any): any {
return value; // ๋ฐํ ํ์
์ด any๋ผ ํ์
์ ๋ณด๊ฐ ์์
}
// ์ ๋ค๋ฆญ ์ฌ์ฉ โ ํ์
์ ๋ณด ์ ์ง
function identity<T>(value: T): T {
return value;
}
const num = identity(42); // T = number, ๋ฐํ ํ์
number
const str = identity('hello'); // T = string, ๋ฐํ ํ์
string์ ๋ค๋ฆญ ์ ์ฝ (Constraints)
// T๋ ๋ฐ๋์ length ์์ฑ์ ๊ฐ์ ธ์ผ ํจ
function getLength<T extends { length: number }>(value: T): number {
return value.length;
}
getLength('hello'); // OK (string์ length๊ฐ ์์)
getLength([1, 2, 3]); // OK (๋ฐฐ์ด์ length๊ฐ ์์)
getLength(42); // ์ค๋ฅ! (number๋ length ์์)์ค์ฉ์ ์ธ ์ ๋ค๋ฆญ ํจ์ ์์
// API ์๋ต์ ์ ๋ค๋ฆญ์ผ๋ก ๊ฐ์ธ๊ธฐ
interface ApiResponse<T> {
data: T;
status: number;
message: string;
}
async function fetchData<T>(url: string): Promise<ApiResponse<T>> {
const response = await fetch(url);
return response.json();
}
// ์ฌ์ฉ
interface User {
id: number;
name: string;
}
const result = await fetchData<User>('/api/users/1');
result.data.name; // TypeScript๊ฐ User ํ์
์์ ์๊ณ ์๋์์ฑ ์ ๊ณต
// ์ฒซ ๋ฒ์งธ ์์ ๋ฐํ
function first<T>(arr: T[]): T | undefined {
return arr[0];
}
// ํค๋ก ๊ฐ์ฒด ๊ฐ ๊ฐ์ ธ์ค๊ธฐ
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user = { id: 1, name: 'Alice' };
getProperty(user, 'name'); // string ๋ฐํ
getProperty(user, 'email'); // ์ค๋ฅ! 'email'์ user์ ํค๊ฐ ์๋์ ํธ๋ฆฌํฐ ํ์ (Utility Types)
TypeScript๋ ์์ฃผ ์ฐ๋ ํ์ ๋ณํ ํจํด์ ๋ด์ฅ ์ ํธ๋ฆฌํฐ ํ์ ์ผ๋ก ์ ๊ณตํ๋ค.
interface User {
id: number;
name: string;
email: string;
password: string;
createdAt: Date;
}
// Partial<T> โ ๋ชจ๋ ์์ฑ์ optional๋ก ๋ง๋ฆ
type UserUpdate = Partial<User>;
// { id?: number; name?: string; email?: string; ... }
// Required<T> โ ๋ชจ๋ ์์ฑ์ ํ์๋ก ๋ง๋ฆ
type RequiredUser = Required<Partial<User>>;
// Readonly<T> โ ๋ชจ๋ ์์ฑ์ ์ฝ๊ธฐ ์ ์ฉ์ผ๋ก ๋ง๋ฆ
type FrozenUser = Readonly<User>;
// frozenUser.name = 'Bob'; // ์ค๋ฅ!
// Pick<T, K> โ ํน์ ์์ฑ๋ง ์ ํ
type UserPreview = Pick<User, 'id' | 'name'>;
// { id: number; name: string }
// Omit<T, K> โ ํน์ ์์ฑ ์ ์ธ
type PublicUser = Omit<User, 'password'>;
// { id, name, email, createdAt } (password ์ ์ธ)
// Record<K, V> โ ํค-๊ฐ ๋งต ํ์
type RolePermissions = Record<string, string[]>;
const permissions: RolePermissions = {
admin: ['read', 'write', 'delete'],
user: ['read'],
};
// Exclude<T, U> โ Union์์ ํน์ ํ์
์ ์ธ
type Status = 'active' | 'inactive' | 'pending' | 'deleted';
type ActiveStatus = Exclude<Status, 'deleted' | 'inactive'>;
// 'active' | 'pending'
// Extract<T, U> โ Union์์ ํน์ ํ์
๋ง ์ถ์ถ
type Numeric = Extract<string | number | boolean, number>;
// number
// ReturnType<T> โ ํจ์ ๋ฐํ ํ์
์ถ์ถ
function getUser() {
return { id: 1, name: 'Alice' };
}
type UserType = ReturnType<typeof getUser>;
// { id: number; name: string }
// Parameters<T> โ ํจ์ ๋งค๊ฐ๋ณ์ ํ์
์ถ์ถ
function createUser(name: string, age: number, email: string) {}
type CreateUserParams = Parameters<typeof createUser>;
// [string, number, string]์ค์ ํ์ฉ ์์
interface Todo {
id: number;
title: string;
completed: boolean;
dueDate: Date;
}
// API์์ ๋ฐ๋ ์์ฑ ์์ฒญ: id์ ์๋ฃ ์ฌ๋ถ๋ ์๋ฒ๊ฐ ์ ํจ
type CreateTodoRequest = Omit<Todo, 'id' | 'completed'>;
// { title: string; dueDate: Date }
// ์
๋ฐ์ดํธ ์์ฒญ: id๋ ํ์, ๋๋จธ์ง๋ ์ ํ
type UpdateTodoRequest = Pick<Todo, 'id'> & Partial<Omit<Todo, 'id'>>;
// { id: number; title?: string; completed?: boolean; dueDate?: Date }React + TypeScript ์ค์
Props ํ์ ์ ์
// interface๋ก Props ์ ์
interface ButtonProps {
label: string;
onClick: () => void;
variant?: 'primary' | 'secondary' | 'danger';
disabled?: boolean;
children?: React.ReactNode;
}
// ํจ์ ์ปดํฌ๋ํธ
const Button: React.FC<ButtonProps> = ({
label,
onClick,
variant = 'primary',
disabled = false,
}) => (
<button
onClick={onClick}
disabled={disabled}
className={`btn btn-${variant}`}
>
{label}
</button>
);
// React.FC ์์ด (๋ ์ ์ฐํ ๋ฐฉ์)
function Card({ title, children }: { title: string; children: React.ReactNode }) {
return (
<div>
<h2>{title}</h2>
{children}
</div>
);
}useState์ ํ์
// ํ์
์ถ๋ก ์ผ๋ก ์ถฉ๋ถํ ๊ฒฝ์ฐ
const [count, setCount] = useState(0); // number
const [name, setName] = useState(''); // string
const [isOpen, setIsOpen] = useState(false); // boolean
// ํ์
์ ๋ช
์ํด์ผ ํ๋ ๊ฒฝ์ฐ
const [user, setUser] = useState<User | null>(null);
const [items, setItems] = useState<string[]>([]);
// ๋ณต์กํ ์ํ
interface FormState {
username: string;
email: string;
errors: Record<string, string>;
}
const [form, setForm] = useState<FormState>({
username: '',
email: '',
errors: {},
});useRef์ ํ์
// DOM ์์ ์ฐธ์กฐ
const inputRef = useRef<HTMLInputElement>(null);
// ๊ฐ ์ ์ง (DOM ์๋ ๊ฒฝ์ฐ)
const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
// ์ฌ์ฉ
const focusInput = () => {
inputRef.current?.focus(); // optional chaining ํ์
};์ด๋ฒคํธ ํ์
// ์์ฃผ ์ฐ๋ ์ด๋ฒคํธ ํ์
๋ค
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
console.log(e.currentTarget.name);
};
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setName(e.target.value);
};
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
};
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') doSearch();
};์์ฃผ ํ๋ ์ค์์ ํด๊ฒฐ๋ฒ
โ any ๋จ์ฉ
// โ ํ์
์คํฌ๋ฆฝํธ ์ฐ๋ ์๋ฏธ๊ฐ ์์ด์ง
function processData(data: any) {
return data.result.items.map((item: any) => item.value);
}
// โ
์ค์ ํ์
์ ์ ์ํ๊ฑฐ๋ unknown + ํ์
๊ฐ๋ ์ฌ์ฉ
interface ApiData {
result: {
items: Array<{ value: string }>;
};
}
function processData(data: unknown) {
if (isApiData(data)) {
return data.result.items.map(item => item.value);
}
throw new Error('Invalid data format');
}โก Type Assertion(as) ๋จ์ฉ
// โ ์ํ โ ์ค์ ๋ก๋ User๊ฐ ์๋ ์ ์์
const user = JSON.parse(jsonString) as User;
user.name.toUpperCase(); // ๋ฐํ์ ์ค๋ฅ ๊ฐ๋ฅ
// โ
๊ฒ์ฆ ํ ์ฌ์ฉ
function parseUser(json: string): User {
const data = JSON.parse(json);
if (typeof data.name !== 'string') throw new Error('Invalid user');
return data as User; // ๊ฒ์ฆ ํ assertion์ ์์
}โข Non-null assertion(!) ๋จ์ฉ
// โ !๋ฅผ ์ต๊ด์ ์ผ๋ก ๋ถ์ด๋ฉด ํ์
์คํฌ๋ฆฝํธ์ ์๋ฏธ ์์
const element = document.getElementById('root')!;
// โ
์ค์ ๋ก null์ด ์๋์ ํ์ธ ํ ์ฌ์ฉ
const element = document.getElementById('root');
if (!element) throw new Error('root element not found');
// ์ด์ element๋ HTMLElementJavaScript โ TypeScript ๋ง์ด๊ทธ๋ ์ด์ ์ ๋ต
์ด๋ฏธ JavaScript๋ก ์์ฑ๋ ํ๋ก์ ํธ๋ฅผ TypeScript๋ก ์ ํํ ๋:
1๋จ๊ณ: tsconfig.json ์ถ๊ฐ, .js โ .ts ํ์ฅ์ ๋ณ๊ฒฝ
"allowJs": true, "strict": false ๋ก ์์
2๋จ๊ณ: ํต์ฌ ๋ชจ๋๋ถํฐ ํ์
์ถ๊ฐ
any๋ฅผ ์ผ๋จ ํ์ฉํ๋ฉด์ ์กฐ๊ธ์ฉ ํ์
์ ์
3๋จ๊ณ: strict ์ต์
ํ์ฑํ
any๋ฅผ ์ค์ ํ์
์ผ๋ก ๋์ฒด
strictNullChecks ์ค๋ฅ ์ฒ๋ฆฌ
4๋จ๊ณ: any ์ ๊ฑฐ, ์ ํธ๋ฆฌํฐ ํ์
ํ์ฉ
์์ ํ TypeScript ์ฝ๋๋ฒ ์ด์คํ ๋ฒ์ ์ ํํ๋ ค ํ์ง ๋ง๊ณ , ํ์ผ ๋จ์๋ก ์ ์ง์ ์ผ๋ก ์ ํํ๋ ๊ฒ์ด ์ค์ฉ์ ์ด๋ค.
TypeScript๋ ์ฒ์์ ํ์ ์ค๋ฅ์ ์จ๋ฆํ๋ ๊ฒ ๊ฐ์์ ๋ฒ๊ฑฐ๋กญ๊ฒ ๋๊ปด์ง ์ ์๋ค. ํ์ง๋ง ํ๋ก์ ํธ ๊ท๋ชจ๊ฐ ์ปค์ง์๋ก TypeScript๊ฐ ์ ๊ณตํ๋ IDE ์๋์์ฑ, ๋ฆฌํฉํ ๋ง ์์ ์ฑ, ๋ฒ๊ทธ ์ฌ์ ์ฐจ๋จ์ ๊ฐ์น๊ฐ ํจ์ฌ ์ปค์ง๋ค.
๋ค์ ๊ธ์์๋ TypeScript๋ก React ์ฑ์ ์ค์ ์์ ์ด๋ป๊ฒ ๊ตฌ์กฐํํ๋์ง, ๊ทธ๋ฆฌ๊ณ API ๋ ์ด์ด๋ฅผ ์ด๋ป๊ฒ ํ์ ์์ ํ๊ฒ ๋ง๋๋์ง ๋ค๋ฃฐ ์์ ์ด๋ค.
๊ด๋ จ ๊ธ
- โก JavaScript ๋น๋๊ธฐ ์ฒ๋ฆฌ ์์ ๊ฐ์ด๋ โ TypeScript์ ํจ๊ป ์ฐ๋ async/await ํจํด
- ๐ React Props์ State ์์ ์ ๋ณต โ TypeScript๋ก React ์ปดํฌ๋ํธ ํ์ ์ ์ํ๊ธฐ
- ๐จ CSS Flexbox & Grid ์์ ์ ๋ณต โ ํ๋ก ํธ์๋ ๊ฐ๋ฐ์ ๋ ๋ค๋ฅธ ํต์ฌ ๊ธฐ์
