

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

# TypeScript 모범 사례 따르기
<a name="typescript-best-practices"></a>

TypeScript는 JavaScript의 기능을 확장하는 언어입니다. 강력한 형식의 객체 지향 언어입니다. TypeScript를 사용하여 코드 내에서 전달되는 데이터 유형을 지정하고 유형이 일치하지 않을 경우 오류를 보고할 수 있습니다. 이 섹션에서는 TypeScript 모범 사례를 간략히 설명합니다.

## 데이터 설명
<a name="describe-data"></a>

TypeScript를 사용하여 코드에 있는 객체 및 함수의 셰이프를 설명할 수 있습니다. `any` 유형을 사용하는 것은 변수 유형 검사를 선택 해제하는 것과 같습니다. 코드에 `any`를 사용하지 않는 것이 좋습니다. 다음 예를 참고하세요

```
type Result = "success" | "failure"
function verifyResult(result: Result) {
    if (result === "success") {
        console.log("Passed");
    } else {
        console.log("Failed")
    }
}
```

## enum 사용
<a name="use-enums"></a>

enum을 사용하여 명명된 상수 세트를 정의하고 코드베이스에서 재사용할 수 있는 표준을 정의할 수 있습니다. 글로벌 수준에서 enum을 한 번 내보낸 다음 다른 클래스에서 해당 enum을 가져와서 사용하도록 하는 것이 좋습니다. 코드베이스에서 이벤트를 캡처할 수 있는 가능한 작업 세트를 만들고 싶다고 가정해 보겠습니다. TypeScript는 숫자 기반 enum과 문자열 기반 enum을 모두 제공합니다. 다음 예에서는 열거형을 사용합니다.

```
enum EventType {
    Create,
    Delete,
    Update
}

class InfraEvent {
    constructor(event: EventType) {
        if (event === EventType.Create) {
            // Call for other function
            console.log(`Event Captured :${event}`);
        }
    }
}

let eventSource: EventType = EventType.Create;
const eventExample = new InfraEvent(eventSource)
```

## 사용자 인터페이스
<a name="use-interfaces"></a>

인터페이스는 클래스에 대한 계약입니다. 계약을 생성하는 경우 사용자는 계약을 준수해야 합니다. 다음 예에서는 인터페이스를 사용하여 `props`를 표준화하고 이 클래스를 사용할 때 호출자가 예상 파라미터를 제공하는지 확인합니다.

```
import { Stack, App } from "aws-cdk-lib";
import { Construct } from "constructs";

interface BucketProps {
    name: string;
    region: string;
    encryption: boolean;

}

class S3Bucket extends Stack {
    constructor(scope: Construct, props: BucketProps) {
        super(scope);
        console.log(props.name);

    }
}
const app = App();
const myS3Bucket = new S3Bucket(app, {
    name: "amzn-s3-demo-bucket",
    region: "us-east-1",
    encryption: false
})
```

일부 속성은 객체를 처음 생성할 때만 수정할 수 있습니다. 다음 예제와 같이 속성 이름 앞에 `readonly`를 입력하여 이를 지정할 수 있습니다.

```
interface Position {
    readonly latitude: number;
    readonly longitute: number;
}
```

## 인터페이스 확장
<a name="extend-interfaces"></a>

인터페이스를 확장하면 인터페이스 간에 속성을 복사할 필요가 없으므로 중복이 줄어듭니다. 또한 코드를 읽는 사람도 애플리케이션의 관계를 쉽게 이해할 수 있습니다.

```
 interface BaseInterface{
    name: string;
  }
  interface EncryptedVolume extends BaseInterface{
      keyName: string;
  }
  interface UnencryptedVolume extends BaseInterface {
      tags: string[];
  }
```

## 빈 인터페이스 사용 금지
<a name="empty-interfaces"></a>

잠재적 위험을 유발할 수 있으므로 빈 인터페이스는 피하는 것이 좋습니다. 다음 예제에는 라는 빈 인터페이스가 있습니다`BucketProps`. `myS3Bucket1` 객체와 `myS3Bucket2` 객체 모두 유효하지만 인터페이스가 어떠한 계약도 적용하지 않기 때문에 서로 다른 표준을 따릅니다. 다음 코드는 속성을 컴파일하고 인쇄하지만 이로 인해 애플리케이션에 불일치가 발생합니다.

```
interface BucketProps {}

class S3Bucket implements BucketProps {
    constructor(props: BucketProps){
        console.log(props);
    }
}

const myS3Bucket1 = new S3Bucket({
    name: "amzn-s3-demo-bucket",
    region: "us-east-1",
    encryption: false,
});

const myS3Bucket2 = new S3Bucket({
    name: "amzn-s3-demo-bucket",
});
```

## 팩토리 사용
<a name="use-factories"></a>

추상 팩토리 패턴에서 인터페이스는 클래스를 명시적으로 지정하지 않고 관련 객체의 팩토리를 만드는 역할을 합니다. 예를 들어, Lambda 함수를 생성하기 위한 Lambda 팩토리를 생성할 수 있습니다. 구문 내에서 새 Lambda 함수를 생성하는 대신 생성 프로세스를 공장에 위임합니다. 이 설계 패턴에 대한 자세한 내용은 Refactoring.Guru 설명서의 [Abstract Factory in TypeScript](https://refactoring.guru/design-patterns/abstract-factory/typescript/example)를 참조하세요.

## 속성에 구조 분해 사용
<a name="destructuring-props"></a>

ECMAScript 6(ES6)에 도입된 구조 분해는 배열이나 객체에서 여러 데이터를 추출하여 자체 변수에 할당할 수 있는 JavaScript 기능입니다.

```
const object = {
    objname: "obj",
    scope: "this",
};

const oName = object.objname;
const oScop = object.scope;

const { objname, scope } = object;
```

## 표준 이름 지정 규칙 정의
<a name="naming-conventions"></a>

이름 지정 규칙을 적용하면 코드베이스의 일관성이 유지되고 변수 이름을 지정하는 방법을 고려할 때 오버헤드가 줄어듭니다. 다음과 같이 하는 것이 좋습니다:
+ 변수 및 함수 이름에는 CamelCase를 사용합니다.
+ 전역 상수에 UPPER\_CASE를 사용하여 변경 불가능한 컴파일 시간 값을 명확하게 표시합니다.
+ 클래스 이름과 인터페이스 이름에는 PascalCase를 사용합니다.
+ 인터페이스 멤버에는 camelCase를 사용합니다.
+ 유형 이름과 enum 이름에는 PascalCase를 사용합니다.
+ CamelCase를 사용하여 파일 이름 지정(예: `ebsVolumes.tsx` 또는 `storage.ts`)

다음은 이러한 권장 명명 규칙의 예를 보여줍니다.

```
// Variables and functions
const userName = 'john';
function getUserData() { }

// Global constants
const MAX_RETRY_ATTEMPTS = 3;
const API_BASE_URL = 'https://api.example.com';

// Classes and interfaces
class DatabaseConnection { }
interface UserProfile { }

// Types and enums
type ResponseStatus = 'success' | 'error';
enum HttpStatusCode { }
```

## var 키워드를 사용하지 마세요.
<a name="var-keyword"></a>

`let` 문은 TypeScript에서 로컬 변수를 선언하는 데 사용됩니다. `var` 키워드와 비슷하지만 `var` 키워드에 비해 범위 지정에 몇 가지 제한이 있습니다. `let`을 사용하여 블록에 선언된 변수는 해당 블록 내에서만 사용할 수 있습니다. `var` 키워드는 블록 범위일 수 없습니다. 즉, 특정 블록(로 표시됨`{}`) 외부에서는 액세스할 수 있지만 정의된 함수 외부에서는 액세스할 수 없습니다. `var` 변수를 다시 선언하고 업데이트할 수 있습니다. `var` 키워드를 사용하지 않는 것이 가장 좋습니다.

## ESLint와 Prettier를 사용해 보세요.
<a name="eslint-prettier"></a>

ESLint는 코드를 정적으로 분석하여 문제를 빠르게 찾아냅니다. ESLint를 사용하여 코드의 모양이나 동작 방식을 정의하는 일련의 어설션(**린트 규칙이라고 함)을 생성할 수 있습니다. ESLint에는 코드 개선에 도움이 되는 자동 수정자 제안도 있습니다. 마지막으로 ESLint를 사용하여 공유 플러그인에서 린트 규칙을 로드할 수 있습니다.

Prettier는 다양한 프로그래밍 언어를 지원하는 잘 알려진 코드 포맷터입니다. 코드 형식을 수동으로 지정하지 않아도 되도록 Prettier를 사용하여 코드 스타일을 설정할 수 있습니다. 설치 후 `package.json` 파일을 업데이트하고 `npm run format` 및 `npm run lint` 명령을 실행할 수 있습니다.

다음 예제에서는 AWS CDK 프로젝트에 대해 ESLint 및 Prettier 포맷터를 활성화하는 방법을 보여줍니다.

```
"scripts": {
    "build": "tsc",
    "watch": "tsc -w",
    "test": "jest",
    "cdk": "cdk",
    "lint": "eslint --ext .js,.ts .",
    "format": "prettier --ignore-path .gitignore --write '**/*.+(js|ts|json)'"
}
```

## 액세스 한정자 사용
<a name="access-modifiers"></a>

TypeScript의 private 한정자는 가시성을 동일한 클래스로만 제한합니다. 속성 또는 메서드에 private 한정자를 추가하면 동일한 클래스 내에서 해당 속성이나 메서드에 액세스할 수 있습니다.

public 한정자를 사용하면 모든 위치에서 클래스 속성과 메서드에 액세스할 수 있습니다. 속성 및 메서드에 대한 액세스 한정자를 지정하지 않으면 기본적으로 퍼블릭 한정자를 사용합니다.

protected 한정자를 사용하면 같은 클래스와 하위 클래스 내에서 클래스의 속성과 메서드에 액세스할 수 있습니다. AWS CDK 애플리케이션에서 하위 클래스를 생성할 것으로 예상되는 경우 보호된 한정자를 사용합니다.

## 유틸리티 유형 사용
<a name="utility-types"></a>

TypeScript의 *유틸리티 유형은* 기존 유형에 대해 변환 및 작업을 수행하는 사전 정의된 유형 함수입니다. 이렇게 하면 기존 유형을 기반으로 새 유형을 생성할 수 있습니다. 예를 들어 속성을 변경 또는 추출하거나, 속성을 선택 사항 또는 필수로 설정하거나, 변경할 수 없는 유형의 버전을 생성할 수 있습니다. 유틸리티 유형을 사용하면 보다 정확한 유형을 정의하고 컴파일 시 잠재적 오류를 포착할 수 있습니다.

### 부분<유형>
<a name="partial-type"></a>

`Partial`는 입력 유형의 모든 멤버를 선택 `Type` 사항으로 표시합니다. 이 유틸리티는 지정된 유형의 모든 하위 집합을 나타내는 유형을 반환합니다. 다음은 `Partial`의 예제입니다.

```
interface Dog {
  name: string;
  age: number;
  breed: string;
  weight: number;
}

let partialDog: Partial<Dog> = {};
```

### 필수<Type>
<a name="required-type"></a>

`Required`는의 반대를 수행합니다`Partial`. 입력 유형의 모든 멤버를 선택 사항으로 지정`Type`하지 않습니다(즉, 필수). 다음은 `Required`의 예제입니다.

```
interface Dog {
  name: string;
  age: number;
  breed: string;
  weight?: number;
}

let dog: Required<Dog> = { 
  name: "scruffy",
  age: 5,
  breed: "labrador",
  weight: 55 // "Required" forces weight to be defined
};
```