
에디터가 추론하지 못하는 타입을 알고 있을 때 as 키워드를 통해 에디터에게 타입을 알려줄 수 있다.
!는 non-null assertion 연산자로 null 타입이 아님을 단언한다.
그러나 타입 단언은 가능하면 지양하는 것이 좋다. 타입 지정을 꼼꼼히 해줄 수록 타입 단언이 필요한 경우는 줄어들 것이다.
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.tsx";
import "./index.css";
// 타입스크립트에서 ! 는 non-null assertion 으로 null 타입이 아님을 의미
// ! 대신 as 키워드로도 타입단언 가능 // as HTMLDivElement
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<App />
</React.StrictMode>,
);
import axios from "axios";
// Person 에 대한 데이터 타입 지정은
// api 문서를 살펴보거나 api 호출 이후 콘솔로그 또는 네트워크창을 통해 확인한 뒤 지정
type Person = { id: number; age: number; height: number };
async function getPerson(): Promise<Person[]> {
const response = await fetch(`http://localhost:4000/people`);
const data: Person[] = await response.json();
return data;
}
getPerson().then((data) => console.log(data));
{
"people": [
{
"id": 1,
"age": 10,
"height": 175
},
{
"id": 2,
"age": 20,
"height": 165
},
{
"id": 3,
"age": 30,
"height": 185
}
]
}
객체 타입의 모든 프로퍼티가 특정 타입의 키와 특정 타입의 값을 가져야 한다고 명시하는 구문
-> 인덱스 시그니처로 정의된 객체 타입의 경우 빈 객체도 유효하게 동작
type StringMap = {
[key: string]: string;
};
const example1: StringMap = {}; // 빈 객체, 유효함
const example2: StringMap = { key1: "value1", key2: "value2" }; // 여러 개의 키-값 쌍, 유효함
console.log(example1); // 출력: {}
console.log(example2); // 출력: { key1: 'value1', key2: 'value2' }
useState<T>에서 T는 상태 데이터의 타입을 의미한다.
const [num, setNum] = useState<number>(10);
const [str, setStr] = useState<string>("");
type Todo = {
id: string;
title: string;
content: string;
isDone: boolean;
createdAt: number;
};
const [todos, setTodos] = useState<Todo[]>;
useState를 쓸 때 가급적 명시적으로 상태를 지정하는 습관을 들이는 것이 좋으며, 특히 객체 타입의 상태를 관리할 때는 명시적 타입 지정이 필요하다.
import React, { useState } from 'react';
type User = {
id: number;
name: string;
};
const MyComponent = () => {
const [user, setUser] = useState<User | null>(null);
const handleLogin = () => {
// 예제 사용자 데이터
const userData: User = {
id: 1,
name: 'John Doe'
};
setUser(userData);
};
return (
<div>
{user ? <p>Welcome, {user.name}</p> : <p>Please log in</p>}
<button onClick={handleLogin}>Login</button>
</div>
);
};
export default MyComponent;
위 예시 코드에서 타입 지정을 하지 않은 채로 초기값만 null로 지정해뒀다면, typescript는 user의 상태를 null로 추론하기에 객체를 할당하려 할 때 타입 에러가 발생할 것이다.
const [settings, setSettings] = useState({ theme: "dark", notifications: true });
setSettings({ thme: "light" }); // 잘못된 속성 이름 (런타임 에러 발생 가능)
또한, 타입을 명시하지 않으면 추후에 잘못된 속성 이름이나 값의 타입이 컴파일 단계에서 잡히지 않을 수도 있기에 타입을 꼭 명시적으로 지정해둬야 한다.
이전 글에서도 다룬 적이 있지만, 제네릭은 일종의 타입 매개변수로 함수 타입을 정의할 때 다양한 타입을 다룰 수 있도록 해준다.
제네릭은 이름 바로 오른쪽에 사용 선언하면 된다.
// 제네릭을 사용하는 타입 별칭
type FlexibleItemType<T> = {
item: T;
}
const stringItem: FlexibleItemType<string> = {item: "Hello"};
// 제네릭을 사용하는 인터페이스
interface FlexibleItemInterface<T> {
item: T;
}
const numberItem: FlexibleItemInterface<number> = {item : 42};
// 제네릭을 사용하는 함수 선언문
function getItem<T>(item: T): T {
return item;
}
const stringResult = getItem<string>("Hello");
// 명시적으로 제네릭타입을 지정하지 않으면 타입추론이 된다.
const bolleanResult = getItem(trun);
// 제네릭을 사용하는 화살표 함수 -> 매개변수 자리 바로 왼쪽에 제네릭 선언
const getItemArrow = <T>(item: T) : T => {
return item;
}
const numberResult = getItemArrow<number>(123);
event 타입 확인은 onChange에 할당된 이벤트핸들러의 매개변수에 해당하는 event에 마우스오버 시 확인할 수 있다.
import { useState } from 'react';
const MyComponent = () => {
const [inputValue, setInputValue] = useState<string>('');
// 이벤트 매개변수에 타입을 지정. 또는 handleChange 자체에 함수 타입을 지정해줄 수도 있다.
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setInputValue(event.target.value);
console.log(event.target.value);
};
return (
<div>
<input type="text" value={inputValue} onChange={handleChange} />
<p>Current Value: {inputValue}</p>
</div>
);
};
export default MyComponent;
객체 타입의 특정 속성 타입을 동적으로 추출할 수 있는 기능이다. 이를 통해 코드의 타입 안정성을 높이고 중복 정의를 방지할 수 있다.
type Person = { age: number; name: string; alive: boolean };
type Age = Person["age"];
위 코드에서 Person["age"]는 Person 타입의 age 속성의 타입(number)을 추출한다.
타입 추론을 통해 type Age = number로 변환된다.
타입 A와 타입 B의 모든 조건을 만족시키는 타입 -> 두 타입의 속성을 모두 포함해여 새 타입을 만든다고 생각하면 된다!
type Person = {
name: string;
age: number;
};
type Employee = {
employeeId: number;
department: string;
};
// 인터섹션 타입을 사용하여 새로운 타입 생성
type PersonEmployee = Person & Employee;
const personEmployee: PersonEmployee = {
name: "Alice",
age: 30,
employeeId: 12345,
department: "Engineering"
};
console.log(personEmployee);