티스토리 뷰
3.1 타입스크립트만의 독자적 타입 시스템
3.1.1 any 타입
- 자바스크립트에 존재하는 모든 값을 오류 없이 받을 수 있다. (타입을 명시하지 않은 것과 동일한 효과)
- any 타입은 자바스크립트의 동적 타이핑으로 돌아가는 것과 비슷한 결과를 가져온다.
- 지양해야 할 패턴이지만 사용해야 한다면?
- 개발 단계에서 임시로 값을 지정해야 할 때
- 어떤 값을 받아올지 또는 넘겨줄지 정할 수 없을 때
- 값을 예측할 수 없을때 암묵적으로 사용
3.1.2 unknown 타입
- any 타입과 유사하게 모든 값이 할당될 수 있다.
- any 제외한 다른 타입으로 선언된 변수에는 unknown 타입 값을 할당할 수 없다.
- 무엇이 할당될지 모르는 상태의 타입
any | unknown |
- 어떤 타입이든 any 타입에 할당 가능 - any 타입은 어떤 타입으로도 할당 가능 (단, never 제외) |
- 어떤 타입이든 unknown 타입에 할당 가능 - unknown 타입은 any 타입 외에 다른 타입으로 할당 불가능 |
- unknown 타입은 어떤 타입이 할당 되었는 지 알 수 없음을 나타내기에 변수의 값을 가져오거나 내부 속성에 접근할 수 없다.
- any와 유사하지만 타입 검사를 강제하고 타입이 식별된 후 사용할 수 있기에 any 보다는 안전하다.
// 할당하는 시점에서는 에러 발생하지 않음.
const unknownFunction: unknown = () => console.log("this is unknown type")
// 여기에서 에러 발생
unknownFunction();
3.1.3 void 타입
- 타입스크립트에서는 함수에서 명시적인 반환문을 작성하지 않으면 void 타입이 사용된다.
- void 타입은 주로 함수 반환 타입으로 사용되지만 함수에 국한된 타입은 아니다.
- void 타입으로 지정된 변수는 undefined 혹은 null 값만 할당할 수 있다.
- 명시적인 의미 부여 관점에서는 undefined와 null 타입 키워드를 사용해 지정하는 것이 바람직하다.
- 타입스크립트 컴파일러가 알아서 함수 타입을 void 로 추론해 준다.
3.1.4 never 타입
- never 타입은 값을 반환할 수 없는 타입을 말한다.
- never 타입은 모든 타입의 하위 타입이다. (never 자신을 제외한 어떤 타입도 never에 할당될 수 없다.)
/*
throw 키워드를 사용하면 에러를 발생시킬 수 있는데, 이는 값을 반환하는 것으로 간주하지 않는다.
따라서, 특정 함수가 실행중 마지막에 에러를 던진다면 반환타입은 never 이다.
*/
function generateError(res: Response): never {
throw new Error(res.getMessage());
}
/*
무한 루프를 실행하는 경우, 값을 반환하지 못한다.
*/
function checkStatus(): never {
while (true) {
// ...
}
}
3.1.5 Array 타입
- 배열은 Array 키워드 외에도 []를 사용해서 직접 타입을 명시할 수 있다.
- 정적 타입의 특성을 살려 명시적인 타입을 선언하여 해당 타입의 원소를 관리하는 것을 강제한다.
const array1: number[] = [1,2,3]
const array2: Array<number> = [1,2,3]
const array3: Array<number | string> = [1, "string"];
const array4: number[] | string[] = [1, "string"];
const array5: (number | string)[] = [1, "string"];
- 튜플은 배열 타입의 하위 타입으로 길이 제한까지 추가한 타입 시스템이라고 볼 수 있다.
- 배열의 특정 인덱스에 정해진 타입을 선언하는 것과 같다.
let tuple: [number] = [1];
tuple = [1,2] // 불가능
tuple = [1, "string"] // 불가능
- 리액트는 16.8 버전부터 도입된 hook이라는 요소 중, useState는 튜플 타입을 반환한다.
import { useState } from "react";
// 첫번째 요소는 훅으로 부터 생성 및 관리되는 상태 값
// 두번째 요소는 해당 상태를 조작할 수 있는 setter 를 의미한다.
const [value, setValue] = useState(false);
// 구조분해할당을 사용해 사용자가 자유롭게 이름을 정의할 수 있다.
const [username, setUsername] = useState("");
// 구조분해할당은 배열뿐만 아니라 객체에 대해서도 적용할 수 있다.
// 하지만, 선언된 속성이름을 통해 값을 가져오므로 튜플보다 유연성은 다소 떨어질 수 있다.
const useStateWithObject = (initialValue: any) => {
// ...
return {value, setValue};
}
const { value, setValue } = useStateWithObject(false);
const { value: username, setValue: setUsername } = useStateWithObject('');
- 스프레드 연산자를 사용하여 특정 인덱스에서 요소를 명확한 타입으로 선언하고 나머지 인덱스에서는 배열처럼 동일한 자료형의 원소를 개수 제한 없이 받도록 할 수 있다.
const httpStatusFromPaths: [number, string, ...string[]] = [
400,
"Bad Request",
"/users/:id",
"/users/:userId"
]
3.1.6 enum 타입
- enum 타입은 열거형이라고도 부르는데 기본적인 추론 방식은 숫자 0부터 1씩 늘려가며 값을 할당한다.
- 주로 문자열 상수를 생성하는 데 사용된다.
- 열거형을 타입으로 가지는 변수는 해당 열거형이 가지는 모든 멤버를 값으로 받을 수 있다.
- 타입 안정성, 명확한 의미 전달과 높은 응집력, 가독성
enum ProgramingLanguage {
Typescript, // 0
Javascript, //1
JAVA, // 2
}
enum ProgramingLanguage {
Typescript = "Typescript",
Javascript = "Javascript",
JAVA = 300,
}
- const enum 역방향으로의 접근을 허용하지 않기 때문에 자바스크립트에서의 객체에 접근하는 것과 유사한 동작을 보장한다.
enum ProgramingLanguage {
Typescript = "Typescript",
Javascript = "Javascript",
JAVA = 300,
}
ProgramingLanguage[200]; // undefined 출력하지만 별다른 에러 발생시키지 않는다.
const enum ProgramingLanguage { // 다음과 같이 선언하면 문제 방지할 수 있다.
Typescript = "Typescript",
Javascript = "Javascript",
JAVA = 300,
}
- 자바스크립트로 변환될 때 즉시실행함수 형식으로 변환되어, 일부 번들러에서 트리쉐이킹 과정 중 즉시 실행 함수로 변환된 값을 사용하지 않는 코드로 인식하지 못하는 경우가 있다.
3.2 타입 조합
3.2.1 교차타입(Intersection)
- 여러 가지 타입을 결합하여 하나의 단일 타입으로 만들 수 있다.
type ProductItem = {
id: number;
name: string;
type: string;
}
// ProductItem 의 모든 멤버와 discountAmount 까지 멤버로 가지게 된다.
type ProductItemWithDiscount = ProductItem & { discountAmount : number };
3.2.2 유니온 타입(Union)
- A 또는 B 타입 중 하나가 될 수 있는 타입을 말하며 A | B로 표기한다.
3.2.3 인덱스 시그니처(Index Signatures)
- 특정 타입의 속성 이름은 알 수 없지만 속성값의 타입을 알고 있을 때 사용한다.
- 인덱스 시그니처를 선언할 때 다른 속성을 추가로 명시할 수 있는데 인덱스 시그니처에 포함되는 타입이어야 한다.
interface IndexSignatureEx {
[key: string]: number | boolean;
length: number;
isValid: boolean;
name: string; // 에러 발생
}
3.2.4 인덱스드 액세스 타입(Indexed Access Types)
- 인덱스드 액세스 타입은 다른 타입의 특정 속성이 가지는 타입을 조회하기 위해 사용된다.
type Example = {
a: number;
b: string;
c: boolean;
}
type IndexedAccess = Example["a"] // number
type IndexedAccess2 = Example["a" | "b"] // number | string
- 배열의 요소 타입을 조회하기 위해 사용하는 경우도 있다.
const PromotionList = [
{ type: "product", name: "chicken" },
{ type: "product", name: "pizza" },
{ type: "card", name: "cheer-up" },
];
// type PromotionItemType = { type: string; name: string }
type PromotionItemType = typeof PromotionList[number];
3.2.5 맵드 타입(Mapped Types)
- 다른 타입을 기반으로 한 타입을 선언할 때 사용하는 문법이다.
- 인덱스드 시그니처 문법을 사용해서 반복적인 타입 선언을 줄일 수 있다.
type Example = { a: number; b: string; c: boolean; } type Subset<T> = { [k in keyof T]? : T[k]; } const aExample: Subset<Example> = {a : 3}; const bExample: Subset<Example> = {b : "hello"};
- 맵드 타입에서는 매핑할 때는 readonly (읽기 전용)와?(선택적 매개변수/옵셔널 파라미터) 수식어로 적용할 수 있다.
- 해당 수식어를 제거할 수도 있는데, 기존 타입에 존재하던 readonly 나? 앞에 - 을 붙여주면 된다.
3.2.6 템플릿 리터럴 타입(Template Literal Types)
- 템플릿 리터럴 문자열을 사용하여 문자열 리터럴 타입을 선언할 수 있는 문법
type Stage =
| "init"
| "select-image"
type StageName = `${Stage}-stage`;
3.2.7 제네릭(Generic)
- 함수, 타입, 클래스 등에서 내부적으로 사용할 타입을 미리 정해두지 않고, 실제로 그 값을 사용할 때 외부에서 타입을 지정하여 사용하는 방식
- 변수명으로 T(Type), E(Element), K(Key), V(Value) 등.. 사용
- 제네릭을 사용할 때 어떤 타입이든 될 수 있다는 개념을 알아야 한다.
- 특정 타입에만 존재하는 멤버를 참조하려고 하면 안 된다. (ex. 배열의 length 속성)
- 써야 한다면 <T extends TypeWithLength>와 같은 제약을 걸어주어야 한다.
- 참고 ) https://rocketengine.tistory.com/entry/Typescript-generic의-extends와-intreface의-extends의-차이
function exampleFunc<T>(arg: T): T[] {
return new Array(3).fill(arg);
}
exampleFunc("hello") // T는 string 으로 추론된다.
interface TypeWithLength {
length: number;
}
function exampleFunc2<T extends TypeWithLength>(arg: T): number {
return arg.length;
}
3.3 제네릭 사용법
- 제네릭의 장점은 다양한 타입을 받게 함으로써 코드를 효율적으로 재사용할 수 있는 것이다.
- 어떤 함수의 매개변수 나 반환 값에 다양한 타입을 넣고 싶을 때 제네릭 사용
- 함수의 매개변수와 반환 타입을 미리 선언하는 호출 시그니처를 사용할 때도 사용
- 외부에서 입력된 타입을 클래스 내부에 적용
- 제네릭 타입은 여러 타입을 상속받을 수 있으며 타입 매개 변수를 여러 개 둘 수도 있다.
- <Key extends string>으로 제약하면 제네릭의 유연성을 잃어버린다.
- <Key extends string | number> 유니온 타입을 상속해서 선언할 수 있다.
- 유니온 타입으로 T가 여러 타입을 받게 할 수 있지만, 타입 매개변수가 여러 개일 때는 하나 더 추가하여 선언한다.
- <T, K>
- 보통 API 응답값의 타입을 지정할 때 많이 활용된다.
export interface MobileResponse<Data> {
data: Data;
statusCode: string;
statusMessage?: string;
}
- 제네릭을 굳이 사용하지 않아도 되는 타입에서 사용하면 코드 길이만 늘어나고 가독성을 해칠 수 있다.
- any를 사용하게 되면 제네릭의 장점과 타입 추론 및 타입 검사를 할 수 있는 이점을 누릴 수 없게 된다.
- 제네릭이 과하게 사용되면 가독성을 해치기에 의미 단위로 분할해서 사용해야 한다.
'study > typescript' 카테고리의 다른 글
우아한 타입스크립트 6장 타입스크립트 컴파일 (0) | 2025.02.23 |
---|---|
우아한 타입스크립트 5장 타입 활용하기 (0) | 2025.02.23 |
우아한 타입스크립트 4장 타입 확장하기 (0) | 2025.02.09 |
우아한 타입스크립트 2장 타입 (0) | 2025.02.03 |
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- 내일배움단
- 스파르타코딩클럽 #비전공자코딩 #아이디어 #개발자멘토 #르탄즈 1기
- 내일배움카드
- DOIT
- 타입확장하기
- 코딩교육
- 스파르타코딩클럽후기
- 우아한타입스크립트
- 코딩
- mongodb
- homebrew
- 웹 스크래핑
- 크롤링
- 1시간만에끝내는직장인코딩용어해설
- ios앱개발
- 르탄즈1기
- 아이디어
- javascript
- 개발일지
- Selenium
- 스파르타 코딩클럽
- 타입스크립트
- 타입활용
- 타입스크립트파일
- 비전공자코딩
- 공부하자...
- iOS 앱개발 기초반
- 개발자멘토
- IOS
- 스파르타코딩클럽
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
글 보관함