튜플을 활용하면 좋은 상황
// chatGPT의 답변
데이터 구조가 고정되고 각 요소의 타입이 명확히 정의되는 상황에서 큰 도움이 됩니다. 이를 통해 타입 안전성을 높이고 코드의 명확성을 개선할 수 있습니다.
타입추론
타입스크립트 타입 추론은 대입할 대상 변수값의 타입이 결정되어 있을 때, 대입할 값과 타입이 일치하지 않는 경우 에러가 발생하는 추론 기능도 있습니다.
자바스크립트를 실행할 때 window 객체는 표준으로 갖는다.
-> window 객체는 JS에서 제공하는 것이 아닌, 모든 브라우저에서 제공하는 객체이다.
-> BOM(Broswer Object Model)
브라우저 창이 열리면 가장 먼저 window 객체가 만들어지고, 그 하위에 브라우저 각 요소에 해당하는 객체가 만들어진다.
cf) 참조: https://pridiot.tistory.com/170
타입 어서션
타입스크립트에서 타입 어서션을 인정하는 것은 대상이 되는 타입보다 구체적이거나 범용적인 타입으로 변환하는 경우.
이 규칙은 보수적이기 때문에 복잡한 어서션을 수행할 때는 잘 표현하기 어렵다. 이런 경우에는 먼저 any로 변환한 뒤, 원하는 타입으로 변환하는 2단계 어서션으로 구현할 수 있다.
eg) const result = (response as any) as User
단, 타입 어서션은 실행 시에 에러를 일으킬 가능성이 있으므로 주의해야 한다. 따라서 가능하다면 타입 어서션 대신 타입 추론이나 타입 가드를 사용하여 안전성을 높이는 것이 좋다.
언제 2단계 assertion을 사용하는가?
- 타입 시스템을 우회하고 싶을 때
// response 객체는 실제로 User 타입과 일치하지만,
// TypeScript 타입 시스템이 이를 명확히 인식하지 못하는 상황을 가정
interface User {
name: string;
age: number;
}
// response가 실제로는 User 타입을 가리키지만, 타입 시스템에서 이를 인식하지 못할 때
const response = {
name: "John Doe",
age: 30
};
// 단일 어서션으로는 불가능한 경우 2단계 어서션을 사용
const result = (response as any) as User;
console.log(result.name); // "John Doe"
console.log(result.age); // 30
타입 앨리어스
객체의 키 이름을 명시하지 않고 타입 앨리어스를 정의할 수도 있습니다. 이것은 인덱스 타입이라 불리는 타입 앨리어스이다. 키 이름과 키 숫자가 미리 정해지지 않은 경우의 객체를 정의할 때 편리하다.
다음 코드는 key(객체의 키)에 문자열, 객체의 값에 문자열을 요청한다.
type Label = {
[key: string]: string
}
인터페이스
타입스크립트의 인터페이스는 타입 앨리어스와 비슷한 기능이지만, 보다 확장성이 높은 열린 기능을 갖고 있다.
인터페이스의 경우 같은 이름의 인터페이스를 선언하여 확장할 수 있지만, 타입 앨리어스를 사용할 때는 같은 이름으로 재정의할 수 없다.
인터페이스는 클래스나 데이터의 한 쪽 측면을 정의한 타입, 즉, 인터페이스에 매치하는 타입이라도 그 값 이외에 다른 필드나 메서드가 있음을 전제로 한다. 한편, 타입 앨리어스는 객체의 타입 자체를 의미한다.
객체 그 자체가 아니라 클래스나 객체의 일부 속성이나 함수를 포함하는 일부 작동을 정의할 때는 인터페이스를 사용하는 것이 적합하다.
Enum 타입
타입스크립트에서는 수치 기반 이외에 문자열 기반의 Enum 타입도 사용할 수 있다. 문자열 기반 Enum 타입을 사용할 때는, 각 멤버를 특정한 문자열의 상수로 초기화해야한다.
enum Direction {
Up = 'UP',
Down = 'DOWN',
Left = 'LEFT',
Right = 'RIGHT'
}
const value = 'DOWN';
const enumValue = value as Direction;
if (enumValue === Direction.DOWN) {
console.log('Down is Selected');
}
문자열 기반(문자열 열거형)의 경우, 상수값은 자동 증가하지는 않지만 문자열로 전달된 값과 Enum의 정수값을 비교할 때 편리하다.
Enum과 비슷한 기능으로 Union 타입이 있다. Union 타입으로도 거의 비슷한 기능을 구현할 수 있어, Union 타입을 선호하는 개발자도 있다.
제네릭
제네릭(Generic)은 클래스와 함수에 대해, 그 안에서 사용하는 타입을 추상화해 외부로부터 구체적인 타입을 지정할 수 있는 기능이다. 바깥쪽에서 지정된 타입이 달라도 작동하도록 할 수 있는 범용적인 클래스나 함수를 정의할 때 편리하다.
제네릭 타입은 타입을 바깥쪽에서 지정해 작동하는 클래스를 기술할 때 편리하다.
리액트 컴포넌트에 제네릭 타입의 클래스를 정의하면 컴포넌트가 받는 props의 타입을 바깥쪽에서 정의할 수 있다.
Union 타입과 Intersection 타입
리터럴 타입
| 로 데이터를 구분하는 리터럴 타입을 사용하면 정해진 문자열이나 수치만 대입할 수 있는 타입(eg, let status: ''start" | "end" // status라는 변수에는 'start' 혹은 'end'라는 문자열만 할당할 수 있다.)
never 타입
에러가 항상 반환되는 함수로 절대로 값이 정상으로 반환되지 않을 때 never 타입을 지정한다.
function error(msg: string): never {
throw new Error(msg);
}
function foo(x: string | number | number[]): boolean {
if (typeof x === 'string') {
return true;
} else if (typeof x === 'number') {
return false;
}
// never를 사용해서 명시적으로 갑이 반환되지 않은 것을 컴파일러에 전달할 수 있다
// never를 사용하지 않으면 타입스크립트는 컴파일 에러를 일으킨다
return error('Never happens');
}
Non-null 어서션 연산자
컴파일 옵션 --strictNullChecks를 지정해 컴파일하면, 타입스크립트는 일반적으로 null일 가능성이 있는 객체에 대한 접근을 에러로 취급한다.
null이 아님을 나타내고 싶을 때 논-널 어서션이라는 기능을 사용해 명시적으로 컴파일러에게 문제가 없음을 전달할 수 있다.
논-널로 나타낼 변수 뒤에 !를 붙인다.
// 실행 시 에러가 될 가능성이 있는 속성에 접근하면 컴파일 에러를 발생(strictNullChecks)
// but 논-널 어서션은 에러를 발생시키지 않아도 된다고 타입스크립트 컴파일러에게 알려줄 뿐이지, 실행 시에 에러가 발생할 가능성은 있다.
// 이와 달리, 옵셔널 체이닝은 트랜스파일되어 생성된 자바스크립트에 null 체크 코드를 추가하기에 실행 시 에러가 발생하지 않는다.
function processUser(user?: User) {
let s = user!.name
}
타입가드
타입스크립트에서 if 문이나 switch 문의 조건 분기에서 타입 체크를 수행할 때, 해당 조건 분기 블록 이후는 변수의 타입이 필터링되는 추론을 수행한다. 이것이 타입가드이다. 다시 말해, 특정 조건을 기반으로 타입이 무엇인지 좁히는데 사용된다.
타입 가드 기능을 사용하면 실행 시 에러를 발생시키기 쉬운 as를 사용하는 타입 어서션보다 안전하게 타입을 사용한 코드를 작성할 수 있다.
옵셔널 속성으로 정의된 값을 if문으로 필터링할 때도 마찬가지로 타입가드 기능을 활용해, if문 안에서는 null 안전한 속성으로서 다룰 수 있다.
is 문법을 사용하여 타입가드를 할 수 있다. 이외에도 typeof나 instanceof를 사용하여 타입가드를 진행한다.
function isString(value: unknown): value is string {
return typeof value === 'string';
}
const value: unknown = "Hello, TypeScript";
if (isString(value)) {
console.log(value.toUpperCase()); // TypeScript는 이제 value가 string임을 안다
} else {
console.log("Value is not a string");
}
keyof 연산자
타입에 대해 keyof 연산자를 사용하면 해당 타입이 가진 각 속성의 타입의 Union 타입을 반환한다. keyof의 결과는 리터럴 타입의 Union 타입으로 취급된다.
활용 방법 검색해보기
인덱스 타입
인덱스 타입(index signature)을 사용하면 객체의 속성이 변할 때, 모아서 타입을 정의할 수 있다. 각 속성에 대응하는 타입을 정의할 수 없을 때 간단하게 기술할 수 있다.
type SupportVersions = {
[env: number]: boolean;
}
let versions: SupportVersions = {
102: false,
103: false,
104: true,
'105': true // error 발생
}
readOnly
타입 앨리어스, 인터페이스, 클래스에 대해 readonly 속성을 지정할 수 있다.
readonly가 지정된 속성은 변경할 수 없다.
type User {
readonly name: string;
readonly gender: string;
}
let user: User = { name: 'hanna', gender: 'Male' }
user.gender = 'Female'; // compile time에 error 발생
자바스크립트의 재대입 불가 기능으로 const 기능이 있으나, 둘의 용도는 다르다. const는 변수의 대입에 대해 수행하는 선언, readonly는 객체나 클래스의 속성에 대해 수행하는 선언으로 컴파일 시 에러를 감지할 수 있다.
또한 Readonly 타입이라는 제네릭 타입도 있다. 아래와 같이 Readonly 타입에 타입 앨리어스를 지정하면, 모든 속성이 변경 불가능한 타입이 작성된다.
type User = {
name: string;
gender: string;
}
type UserReadonly = Readonly<User>
let user: User = { name: 'Hanna', gender: 'Male' };
let userReadonly: UserReadonly = { name: 'Hanna', gender: 'Male' };
user.name = 'Jinho' // OK
userReadonly.name = 'Jinho' // 컴파일 시 에러가 발생한다.
unknown
unknown은 any와 마찬가지로로 모든 값을 대입할 수 있는 타입이다. 하지만 any와 달리 대입된 값 상태 그대로는 임의의 함수나 속성으로 접근할 수 없다.
typeof나 instanceof 등을 사용해 타입 안전한 상태를 만든 뒤, 변수값에 접근하는 함수 등의 처리를 실행할 수 있다.
unknown은 임의의 타입을 대입할 수 있는 any와 같은 특성을 가지서, 보다 타입이 불명확한 값을 나타내는 기능을 강조한 것.
변수를 사용할 때는 타입을 지정함으로써 any로는 할 수 없었던 컴파일 시 에러를 사전에 감지할 수 있다. 결과적으로 any를 사용하는 것보다 안전한 코드를 작성할 수 있다.
타입 정의 파일
타입스크립트 프로젝트에 자바스크립트 라이브러리를 로딩해서 실행할 수 있지만, 타입 정의 정보가 없을 때는 타입 safe한 코드를 작성할 수 없다.
그래서 타입스크립트에는 자바스크립트 모듈에 대해, 타입 정보를 부여할 수 있는 타입 정의 파일이라는 구조를 제공한다. 이를 도입하는 방법은 크게 2가지이다.
1. @types로 대표되는 공개된 타입 정의 파일을 도입한다. 2. 타입 정의 파일을 직접 작성한다.
- 타입 정의 파일 도입
첫 번째는 @types/[라이브러리명]으로 공개된 타입 정의 파일을 설치하는 방법 / 별도로 '@types/~'로 설치하지 않더라도 라이브러리에 포함된 경우가 있다.
- 타입 정의 파일 작성
의존하는 js 라이브러리가 타입 정의 파일을 포함하고 있지 않거나, 공개되어 있지 않을 때 직접 .d.ts라는 확장자를 가진 타입 정의 파일을 설치하고, 로딩해서 사용할 수 있다.
./lib/hello.js라는 js 유틸리티 함수가 존재한다고 가정.
export.hello = function(name) {
console.log(name);
}
.lib/hello.d.ts라는 타입 정의 파일을 작성한다.
export function hello(name: string): void
위와 같이 정의 파일을 설치하면 js 유틸리티 함수가 타입 정보를 가진 ts 코드로 작동한다.
ESLint
ESLint는 자바스크립트나 타입스크립트 코드를 해석해 문제가 있는 위치를 지적해 코드 품질을 높이는 데 도움을 주는 도구이다.
Prettier는 코드를 포맷팅(형태를 정리해서 출력)하는 것이 주목적인 반면, ESLint는 코드를 해석해 문제를 감지하는 것(lint)이 주목적이다. 많은 FE 개발자들이 prettier와 ESLint를 함께 사용하고 있다.
ESLint는 100가지 이상의 다양한 규칙에 대해 코드를 해석할 수 있으며, 설정도 커스터마이즈할 수 있다.
//.eslintrc.js
{
"rules": {
"semi": ["error", "always"],
"quotes": ["error", "double"],
}
}
위 설정 파일의 semi와 quotes는 각각 세미콜론과 따옴표를 어떻게 취급하는지 나타내는 규칙을 설정한 것이다.
배열의 첫 번째 값은 에러 수준을 나타낸다.
- off 또는 0 // 규칙 비활성화
- warn 또는 1 // 규칙을 경고로 취급
- error 또는 3 // 규칙을 에러로 취급
배열의 두 번째 값은 각각 규칙에 전달하는 설정값이다.
컴파일 옵션
noImplicitAny
- 타입이 지정되지 않고 타입스크립트가 컨텍스트에 따라 타입을 추측할 수 없는 경우, 컴파일러는 일반적으로 any를 사용한다. 이것을 암묵적인 any라고 한다.
- 하지만 any는 타입 체크를 수행하지 않으므로 되도록 사용을 자제해야 한다.
코딩 스타일 가이드
타입스크립트에서는 세미콜론을 붙일 것을 권장하지만, Next.js에서는 세미콜론을 붙이지 않는다.
따라서 스타일 가이드에는 언어마다의 사고방식이 있기 때문에, 유일한 가이드는 존재하지 않는다. 다만 몇 가지를 참조하여 사용하면 된다.
JS 표준 스타일
- 세미콜론을 생략하는 것이 특징인 모던한 스타일 가이드
- https://github.com/standard/standard/blob/master/docs/README-kokr.md
에어 비앤비 스타일 가이드
- 많은 스타일이 베스트 프랙티스로 사용된다
- https://github.com/airbnb/javascript
구글 스타일 가이드
- 타입스크립트에 관한 내용도 공개하고 있다
- https://github.com/google/styleguide
Typescript Deep Dive 스타일 가이드
- 타입스크립트에서 인기 있는 스타일 가이드
- https://basarat.gitbook.io/typescript/styleguide
Next.js는 v11.0 이후 ESLint를 기본으로 설정하게 됬다. 리액트 기반의 것을 확장한 것으로, 독자적인 ESLint 플러그인인 eslint-plugin-next를 탑재하고 있다.
Next.js의 ESLint 공식 가이드 - https://nextjs.org/docs/basic-features/eslint#eslint-plugin
Configuring: ESLint | Next.js
Next.js reports ESLint errors and warnings during builds by default. Learn how to opt-out of this behavior here.
nextjs.org
타입스크립트 컴파일러
tsc라는 명령어를 실행했을 때 타입스크립트의 컴파일러는 소스 코드를 해석해서 js로 변환한다. 이때 컴파일러가 처리하는 과정은 대개 아래와 같다.
1. 스캐너(Scanner): 타입스크립트 소소 코드를 읽고, 각각의 문법 요소를 위치 정보를 가진 토근으로 변환한다.
2. 파서(Parser): 스캐너가 작성한 토큰을 받아 추상 구문 트리(Abstract Syntax Tree, AST)로 변환한다.
3. 바인더(Binder): AST를 기반으로 타입 체크의 기본이 되는 심벌을 작성한다.
4. 체커(Checker): 타입 체크를 실행한다. 컴파일러에서 가장 큰 부분이다(23년 5월 기준, 4만 라인 이상의 코드)
5. 에미터(Emitter): AST와 체커의 결과를 바탕으로 타입스크립트에서 자바스크립트로 변환해 출력한다.
'next.js' 카테고리의 다른 글
(타입스크립트, 리액트, Next.js로 배우는 실전 웹 애플리케이션 개발) Ch1 Next.js와 타입스크립트를 활용한 모던 개발 (0) | 2024.07.25 |
---|---|
Next.js 에서 client component와 server component 구성 (1) | 2023.12.05 |