eatthefrog
타입스크립트 기초 본문
자바스크립트와 타입 스크립트 (TS((JS))
타입스크립트를 자바스크립파일로 변환하는 컴파일러가 필요하다.
Benefits
- Static typing(Type Checking)
- Staticaly-typed: C++, C#, Java
- dynamically-typed: JS, 파이썬, 루비
- Code completion
- Refactorin
- Shorthand notations
자바스크립트의 동적 타이핑 문제로 재할당에 의해 변수의 타입은 언제든지 동적으로 변할 수있는건 const로 해결할 수 있는 문제다. 근데 왜 굳이 TypeScript를 사용할까?
const의 한계와 TypeScrit의 이점
1. 객체와 배열의 내부 변경
// ☑️ const
const user = { name: "김철수", age: 25 };
user.age = "스물다섯"; // 타입이 number에서 string으로 변경됨
user.newProperty = true; // 새로운 속성 추가
const numbers = [1, 2, 3];
numbers.push("4"); // string이 number 배열에 추가됨
// ✅ TypeScript: 타입 체크로 런타임 에러 방지
interface User {
name: string;
age: number;
}
const user: User = { name: "김철수", age: 25 };
user.age = "스물다섯"; // 컴파일 에러 발생
2. 함수 매개변수와 반환값
// ☑️ const
const calculateTotal = (items) => {
// items가 배열인지, 객체인지, 숫자인지 알 수 없음
return items.reduce((sum, item) => sum + item.price, 0);
};
// 런타임 에러 발생 가능
calculateTotal("잘못된 데이터");
// ✅ TypeScript: 함수 시그니처 명확화
const calculateTotal = (items: Array<{price: number}>): number => {
return items.reduce((sum, item) => sum + item.price, 0);
};
3. API 응답 데이터
// ☑️ const
const fetchUserData = async () => {
const response = await fetch('/api/user');
const data = await response.json();
// data의 구조를 알 수 없음
return data.user.profile.name; // 존재하지 않는 속성에 접근할 수 있음
};
타입표기와 기본 자료형
타입스크립트의 타입 체킹 예제
let score: number = 90;
let studentName: stirng;
studentName = 'Jogn';
score = 95; //✅ 타입스크립트도 let 변수 재할당 가능!
score = "95"; //❌ 타입스크립트의 타입 체킹
타입 스크립트에서 변수를 할당하는 3가지 방법
// 1. 명시적 타입 선언 + 초기화
// 타입: number로 명시적 지정, 초기값 90
let score: number = 90;
score1 = 95; // ✅ 가능
score1 = "A+"; // ❌ 에러: string을 number에 할당 불가
// 2. 타입 추론 + 초기화
// 타입: number로 자동 추론, 초기값 90
let score = 90;
score2 = 95; // ✅ 가능
score2 = "A+"; // ❌ 에러: string을 number에 할당 불가
// 3. 타입 미지정 + 초기값 없음
// 타입: any로 추론, 초기값: undefined
let score;
score3 = 90; // ✅ 가능
score3 = "A+"; // ✅ 가능 (any 타입이라서)
score3 = true; // ✅ 가능 (any 타입이라서)
any 타입
: 변수를 선언만하고 할당은 하지 않으면 'any' 타입으로 지정되고, 어떤 자료형이든 할당될 수 있다, 이는 타입스크립트를 사용하는 의미가 없게 하므로 지양해야할 코드다.
하지만 타입 정의가 없는 외부 라이브러리를 사용하거나 API로부터 데이터를 받아올때 다루어야할 데이터의 타입을 미리 알 수 없는 등의 상황에서 타입스크립트의 안전장치를 잠시 꺼두는 용도로 'any'가 사용된다.
//When 'any' is useful -working with third-party libraries
// data라는 매게변수를 받아서 반환하는 함수이고 이 data로 어떤 타입의 값이 주어질지는 예측할 수 없다.
// 의도된 타입의 값이 전달되었을 경우 'someProperty'속성에 접근해서 'someMethod'를 호출한 결과를 반환할 것이다.
// 만약 다른 타입이더라도 옵셔널 체이닝을 사용하여 오류를 방지한다. 그리고 OR 연산자를 사용해 의도된 타입이 아니라면 해당 데이터 자체 (data)를 반환한다.
function processData(data: any) {
return data.someProperty?.someMethod?.() ||data;
}
unknown 타입
'any'가 타입을 모르는 데이터에 대해 관대해지는 반면 'unknown'은 오히려 엄격해진다.
'any'는 타입을 모르니까 "뭐든 들어와"라면 unknown은 타입을 모르니까 "뭐든 들어오지마"로 일단 모든걸 금지한다.
let anyVar: any: 10;
let unknownVar: unKnown = 10;
let anyNumber: numner = anyVar; //✅
anyVar.toFixed(2); //✅
let unknownVar: number = unknownVar; //❌
unknownVar,toFixed(2); //❌
그래서 unKnown타입을 사용하려면 타입 가드라는 안전장치가 필요하다. 쉽게 말해, '만약 이 값의 타입이 무엇무엇이라면'과 같은 조건들을 두고 코딩하는 것이다.
unknown 타입과 타입가드 예시
// unKnown 타입의 값을 처리하는 함수 예시
// 아래 처럼 해당 값의 실제 타입에 따른 코드를 각각 작성해준다.
// function 함수명(매개변수: 매개변수타입): 반환타입 { 함수본문 }
// val: unknown → 매개변수 val은 unknown 타입
// : string → 함수는 반드시 string 타입을 반환해야 함 "이 함수는 어떤 입력을 받든 항상 문자열을 반환한다"
function processValue(val: unknown): string {
if (typeof val === 'string') {
return val.toUpperCase(); //✅ string 반환
}
if (typeof val === 'number') {
return val.toFixed(2); //✅ string 반환 (toFixed는 string 리턴)
}
return String(val); // string 반환
}
console.log(processValue('hello')); //✅ "HELLO"
console.log(processValue(42)); //✅ "42.00"
console.log(processValue(true)); //✅ "true"
unknown과 타입단언 as 예시
// 문자열 값이 들어있지만 타입은 'unknown'으로 지정된 변수 unknownValue
let unknownValue: unknown = "Hello, TypeScript";
// Type assertion - when you're certainof the type
// 괄호안에 'as'연산자를 사용하해서 해당 변수의 값이 문자열 타입임을 나타낸다.
// 이렇게 작성하면 타입스크립트는 이를 신뢰하고 컴파일 단계에서 오류를 발생시키지 않는다.
let stringLegnth = (unknwonValue as stirng).length;
// Type guard -safer
if(typeof unknownValue === 'stirng') {
let length = unknwonvalue.length;
}
unknown과 any를 적절히 활용하여 외부 데이터를 안전하기 처리하기 예제
function processUserData(user: unknown): string {
// 1단계: 객체인지 확인 (Type Guard)
if (typeof user === 'object' && user !== null) {
// 2단계: name 속성 존재 및 타입 확인
if ('name' in user && typeof (user as any).name === 'string') {
return (user as any).name.toUpperCase();
}
}
return 'Invalid user data';
}
console.log(processUserData({ name: 123 })); // "Invalid user data"
console.log(processUserData("John Doe")); // "Invalid user data"
unknown - 안전한 시작점
- unknown: 어떤 타입인지 모르니까 일단 안전하게 시작
- 바로 user.name 접근 불가 → 타입 체크 필요
any - 제한적이고 안전한 사용
- 'name' in user로 속성 존재는 확인했지만
- TypeScript는 여전히 user.name의 타입을 모름
- 따라서 (user as any).name으로 접근
유니온 타입
: 여러 타입 중 하나가 될 수 있는 타입을 나타내며, | 기호로 사용한다.
// 문자열 또는 숫자
let value: string | number;
value = "hello"; // ✅ 가능
value = 42; // ✅ 가능
value = true; // ❌ 에러
타입 스크립트 배열 선언 방법 2가지
1. 타입 [] 문법
let numbers: number[] = [1, 2, 3, 4, 5];
let scores: number[] = [];
2. Array<타입> 문법(제네릭 문법)
let fruits: Array<string> = ['Apple', 'Banana', 'Orange'];
타입 안전성 확인
let scores: number[] = [];
scores.push(95); // ✅ 가능 (number)
scores.push(88); // ✅ 가능 (number)
scores.push("A+"); // ❌ 에러 (string은 불가)
let colors = ['Red', 'Green', 'Blue']; // string[]로 타입 추론
colors.push(123); // ❌ 에러 (number는 불가)
타입 추론 VS 명시적 선언
// 타입 추론 (권장)
let colors = ['Red', 'Green', 'Blue']; // string[]로 자동 추론
// 명시적 선언
let colors: string[] = ['Red', 'Green', 'Blue'];
// 빈 배열은 명시적 선언 필요
let scores: number[] = []; // 타입 지정 필요
다양한 배열 타입 예제
// 유니언 타입 배열
let mixed: (string | number)[] = [1, "hello", 2, "world"];
// 대괄호([])를 붙여서, 객체 배열을 저장할 수도 있다.
let users: {
name: string;
age: number
}[] = [
{ name: "김철수", age: 25 },
{ name: "이영희", age: 30 }
];
let people: {
name: string;
age: number;
}[]'
// 읽기 전용 배열
let readonlyNumbers: readonly number[] = [1, 2, 3];
// readonlyNumbers.push(4); // ❌ 에러 (수정 불가)
타입 스크립트 배열 고차 함수의 타입추론과 반환 타입 코드 예제
- 타입 스크립트는 배열 고차 함수의 입력/출력 타입을 자동 추론
- 각 함수별로 적절한 반환 타입 제공 (map: 변환, filter: 같은 타입, find: 타입 | undefined)
- 컴파일 타입에 대한 타입 안전성 보장
1. mpa() 배열 반환
// 타입 변환) map은 각 요소를 다른 타입으로 변환 가능
// stirng[] -> number[]
const names: string[] = ['Alice', 'Bob', 'Charlie', 'David'];
const nameLengths: number[] = names.map(name => name.length);
// 결과: [5, 3, 7, 5]
2. filter() 배열 필터링
// 타입 유지) 조건에 맞는 요소만 선택
// string[] -> string[](같은 타입 유지)
const longNames: string[] = names.filter(name => name.length > 4);
// 결과: ['Alice', 'Charlie', 'David']
3. find() 단일 요소 찾기
// 반환타입) 첫 번재로 조건에 맞는 요소 반환
// string | undefined (찾지 못할 수도 있음)
const foundName: string | undefined = names.find(name => name.startsWith('B'));
// 결과: 'Bob' 또는 undefined
타입 추론의 장점
// 타입스크립트가 자동으로 추론
const names = ['Alice', 'Bob', 'Charlie']; // string[]
// map 결과 자동 추론
const lengths = names.map(name => {
// name은 자동으로 string 타입
return name.length; // 반환값은 number
}); // lengths는 number[]
// filter 결과 자동 추론
const shortNames = names.filter(name => {
// name은 string 타입
return name.length < 5; // 조건은 boolean
}); // shortNames는 string[]
다양한 고차 함수 예제
const numbers = [1, 2, 3, 4, 5];
// reduce - 누적 계산
const sum: number = numbers.reduce((acc, num) => acc + num, 0);
// some - 조건 만족 여부
const hasEven: boolean = numbers.some(num => num % 2 === 0);
// every - 모든 요소 조건 만족 여부
const allPositive: boolean = numbers.every(num => num > 0);
// forEach - 각 요소 순회 (반환값 없음)
numbers.forEach(num => console.log(num)); // void
타입 안전성 보장
// 타입스크립트의 단계별 타입 체크
const names: string[] = ['Alice', 'Bob'];
names.map(name => {
// 1. name의 타입 확인: string
// 2. name에 사용 가능한 메서드 확인
// 3. 반환값 타입 확인
return name.toUpperCase(); // ✅ string → string (정상)
return name.toFixed(2); // ❌ string에 toFixed 없음
});
names.filter(name => {
// 1. name의 타입 확인: string
// 2. 반환값이 boolean인지 확인
return name.length > 3; // ✅ boolean (정상)
return name.length; // ❌ number (boolean 아님)
});
타입스크립트 튜플
- 튜플: 서로 다른 타입, 고정 길이, 순서 중요
- 배열: 같은 타입, 가변 길이, 순서 상관없음
- 활용 예시: 함수의 다중 반환값, 좌표
기본 튜플 사용법
// 첫 번째 요소는 반드시 stirng
// 두 번재 요소는 반드시 number
// 정확히 2개 요소만 허용
let person: [string, number] = ['John', 30];
console.log(person[0]); // 'John' (string)
console.log(person[1]); // 30 (number)
타입 안전성
// ❌ 에러: 순서가 맞지 않음
person = [30, 'John'];
// ❌ 에러: 길이가 맞지 않음 (3개 요소)
person = ['John', 30, true];
구조 분해 할당
// 각 변수가 올바른 타입으로 자동 추론됨
const [firstName, age] = person;
console.log(firstName); // 'John' (string 타입)
console.log(age); // 30 (number 타입)
선택적 요소 (Oprional)
// boolean?: 세 번째 요소는 있어도 되고 없어도 됨
type OptionalTuple = [string, number, boolean?];
const complete: OptionalTuple = ['Jane', 25, true]; // ✅ 3개 요소
const partial: OptionalTuple = ['Mike', 40]; // ✅ 2개 요소 (3번째 생략)
일반 배열과의 차이점
// 튜플 - 타입과 순서 고정
let tuple: [string, number] = ['John', 30];
tuple[0] = 'Jane'; // ✅ string만 가능
tuple[1] = 25; // ✅ number만 가능
// 배열 - 모든 요소가 같은 타입
let array: string[] = ['John', 'Jane', 'Mike'];
array.push('Tom'); // ✅ 길이 제한 없음
타입스크립트 객체 타입 선언과 에러 검증 예시
타입 스크립트는 객체 생성 시점에 모든 속성이 올바른 타입인지, 필수 속성이 누락되지 않아는지 검증해서 런타임 에러를 미리 방지한다.
- 객체의 구조와 타입을 미리 정의
- 컴파일 타임에 타입 불일치와 누락된 속성 검출
- 코드 작성 시 자동완성과 에러 방지 제공
객체 타입 선언 방법
// 인라인 타입 선언
//name:string - name 속성은 문자열이어야함
//age:number - age 속성은 숫자여야 함
const person: { name: string; age: number } = {
name: "John",
age: 25,
};
타입 안전성 검증
// 1. 타입 불일치 에러
const wrongPerson1: { name: string; age: number } = {
name: "John",
age: "25", // ❌ 에러: string을 number에 할당 불가
};
// 2. 필수 속성 누락 에러
const wrongPerson2: { name: string; age: number } = {
name: "Mark",
// ❌ 에러: age 속성이 누락됨
};
올바른 사용 예시
// ✅ 정상: 모든 타입이 일치
const person: { name: string; age: number } = {
name: "John",
age: 25,
};
// ✅ 정상: 타입 추론 활용
const person2 = {
name: "Jane", // string으로 추론
age: 30, // number로 추론
};
선택적 속성
// ? 를 사용한 선택적 속성
const person3: { name: string; age?: number } = {
name: "Mike",
// age는 있어도 되고 없어도 됨
};
const person4: { name: string; age?: number } = {
name: "Sara",
age: 28, // 있어도 됨
};
인터페이스로 개선
// 재사용 가능한 타입 정의
interface Person {
name: string;
age: number;
}
const person: Person = {
name: "John",
age: 25,
};'프론트엔드 노트' 카테고리의 다른 글
| 자바스크립트 동작 연산자 (5) | 2025.07.10 |
|---|---|
| 타입스크립트 제네릭 (0) | 2025.07.08 |
| 자바스크립트) 비동기함수 with 별코딩 (0) | 2025.07.05 |
| Skyscanner) Task 1: Create a Backpack React web app (진행중) (0) | 2025.05.16 |
| Expo 빌드 & App Store 배포하기(2) (0) | 2025.04.30 |