TypeScript Handbook 정리2 - Everyday Types
반응형

안녕하세요 😉

유유자적한 개발자 유로띠 입니다 😀

 

👏👏👏👏

 

 

 

TypeScript에 대해서 알아보겠습니다.

 

이번 포스팅은 타입스크립트 공식 핸드북의 원본과 해석본을

읽고 정리하는 글입니다.

 

TypeScript Handbook

TypeScript Handbook 정리 - The Basics

TypeScript - Everyday Types

TypeScript - Narrowing

TypeScript - More on Functions

TypeScript - Object Types

TypeScript - Type Manipulation

TypeScript - Classes

TypeScript - Modules

TypeScript - tsConfig

 

 

Everyday Types

에 대해서 알아보겠습니다

 

 

🎉 TypeScript


Everyday Types

 

🟢 The primitives (원시 타입): string, number, boolean

 

string(문자열)

문자열을 나타냅니다.

let apple: string = 'Apple';
let day1: string = 'Day1';

number(숫자)

모든 부동 소수점 값을 사용할 수 있습니다.

let integer: number = 1207;
let float: number = 3.141592;

 

Boolean(불린)

단순한 참(true) / 거짓(false) 값을 나타냅니다.

let isUsed: boolean = true;

 

🟢 Arrays(배열)

순차적으로 값을 가지는 배열을 나타내며, 두 가지 방법으로 선언이 가능합니다.

let language: string[] = ['node', 'kotlin', 'go'];

let language: Array<string> = ['node', 'kotlin', 'go'];

 

🟢 any(모든 타입)

어떤 타입의 값도 할당할 수 있습니다.

다양한 값을 포함하는 배열을 나타낼 수도 있습니다.

let obj: any = { x: 0 };

obj.bar = 100;
obj = 'day1';
obj = {};
obj = null;

const list: any[] = [1, true, 'day1'];

 

🟢 unknown (알 수 없는 타입)

최상위 타입인 unknown은 any와 같이 어떤 타입의 값도 할당할 수 있지만, 다른 타입에는 할당할 수없습니다.

다만, 타입을 단언하면 할당할 수 있습니다.

let obj: unknown = '언노운';

let str: string = obj; //'unknown' 형식은 'string' 형식에 할당할 수 없습니다.ts(2322)

let str: string = obj as string;

 

🟢 Type Annotations on Variables

const, var, let과 같은 선언자로 변수를 선언할 때, 변수의 타입을 특정하기 위해 선택적으로 타입 선언을 합니다.

let name: string = 'yu';

String name = 'yu'; (x)

 

다만, 타입 스크립트는 자동으로 타입을 추론하여 타입을 적용합니다.

숫자 1207을 할당하여 number 타입으로 추론되었고, 이후 'type'이라는 string 타입의 값은 할당할 수 없기에 에러가 발생됩니다.

let num = 1207;
num = "type"; //'string' 형식은 'number' 형식에 할당할 수 없습니다.ts(2322)

타입스크립트가 타입을 추론하는 경우는 다음과 같습니다.

🔷 초기화된 변수

🔷 기본값이 설정된 매개 변수

🔷 변환 값이 있는 함수

 

 

#코틀린 variables와 비슷한 점

val a: Int = 1  // immediate assignment
val b = 2   // `Int` type is inferred
val c: Int  // Type required when no initializer is provided
c = 3       // deferred assignment

 

 

🟢 Functions (함수)

Parameter Type Annotations (매개변수의 타입)

함수를 선언할 때, 매개변수의 뒤에 타입을 선언할 수 있습니다.

이를 통해 어떤 타입을 받을 수 있는지 알 수가 있습니다.

function greet(name: string) {
	console.log('Hello, ' + name);
}

 

Return Type Annotations (반환 타입)

반환 값의 타입을 선언할 수 있습니다.

function greet(name: string): string {
  return "Hello, " + name;
}

 

Anonymous Functions

다른 함수 선언과 다르게 타입스크립트는 문맥상으로 타입을 결정합니다.

names이란 배열은 string으로 선언하지 않았지만, 문맥상 string 타입이기 때문에 s 매개변수가 타입이 선언되지 않았음에도 s의 타입을

추론하여 string으로 판단하여서 toUpperCase()를 사용해도 에러가 발생되지 않습니다.

const names = ["Alice", "Bob", "Eve"];

names.forEach(function (s) {
  console.log(s.toUpperCase());
});

이러한 프로세스를 contextual typing(문맥상의 타이핑)이라고 합니다.

 

🟢 Object Types

원시 타입(primitives: number, string, boolean, bigint, null, undefined)이 아닌 타입을 나타냅니다.

let obj: object = {};
let obj: object = [];
let obj: object = null;

여러 타입의 상위 타입이기 때문에 유용하지 않고 보다 정확한 타입 지정을 하기 위해 객체 속성들에 대한 타입을 개별적으로

지정할 수 있습니다.

 

Optional Properties

프로퍼티의 일부 또는 전부를 옵셔널로 특정할 수 있습니다.

속성에 ?를 추가하면  선택적 속성으로 정의할 수 있습니다.

function add(obj: { x: number; y?: number }): number {
  return obj.x + (obj.y ?? 0);
}

add({ x: 2 });
add({ x: 2, y: 10 });

 

자바스크립트에서 존재하지 않은 프로퍼티에 접근하면, 런타임 에러 대신 undefined라는 값을 반환합니다.

때문에 옵셔널 프로퍼티로부터 값을 읽을 때, undefined를 체크하여 없는 경우 0을 리턴하도록 하였습니다.

 

위 예제는 다음 예제와 동일합니다.

function add(obj: { x: number; y: number | undefined }): number {
  return obj.x + (obj.y || 0);
}

add({ x: 2, y: undefined });
add({ x: 2, y: 10 });

 

🟢 Union Types

2개 이상의 타입을 허용하는 경우 유니언이라고 합니다.

| (vertical bar)를 통해 타입을 구분합니다.

let union: (string | number);
union = 'Hello type!';
union = 123;

union = false; //'boolean' 형식은 'string | number' 형식에 할당할 수 없습니다.ts(2322)

 

모든 타입이 동작하는 작업만을 실행하도록 허락합니다.

다음 예제처럼 number 타입에서 동작하지 않는 toUpperCase는 사용할 수 없습니다.

let union: (string | number);
union = 'Hello type!';
union = 123;

union.toUpperCase(); //'number' 형식에 'toUpperCase' 속성이 없습니다.ts(2339)

 

string 타입에만 toUpperCase를 사용하려면 어떻게 해야 할까요?

방법은 타입을 코드로 좁히는 Narrowing 방법을 진행합니다.

function narrowing(union: string | number) {
  if (typeof union === "string") {
    return union.toUpperCase();
  } else {
    return union;
  }
}

narrowing("apple");
narrowing(12);

 

🟢 Type Aliases (타입 별칭)

특정 타입에 대해 이름을 지정할 수 있는 기능입니다.

type 키워드를 사용해 새로운 타입 조합을 만들 수 있습니다.

type scoreType = number;
type resultType = number | string;

function printScore(score: number): scoreType {
  return score;
}

printScore(11);

 

 

🟢 Interfaces

인터페이스는 타입스크립트 여러 객체를 정의하는 일종의 규칙이며 구조입니다.

Iemployee에서I는 Interface를 의미합니다.

 

속성에 ?를 사용하면 선택적 속성으로 정의할 수 있습니다.

interface Iemployee {
  name: string;
  id: number;
  isAdult?: boolean; //Optional property
}

let employee: Iemployee = {
  name: "Neo",
  id: 123,
  isAdult: true,
};

let employee2: Iemployee = {
  name: "Neo",
  id: 123,
};

 

읽기 전용 속성 (Readonly properties)

readonly 키워드를 사용하면 초기화된 값을 유지해야 하는 읽기 전용 속성을 정의할 수 있습니다.

interface Iemployee {
  name: string;
  readonly id: number;
  isAdult?: boolean; //Optional property
}

let employee: Iemployee = {
  name: "Neo",
  id: 123,
  isAdult: true,
};

employee.id = 456; //읽기 전용 속성이므로 'id'에 할당할 수 없습니다.ts(2540)
employee.name = "spring";

 

모든 속성이 readonly일 경우 유틸리티 타입을 활용할 수 있습니다.

interface Iemployee {
  name: string;
  id: number;
}

//Utility
let employee: Readonly<Iemployee> = {
  name: "Neo",
  id: 123,
};

employee.id = 456; //읽기 전용 속성이므로 'id'에 할당할 수 없습니다.ts(2540)
employee.name = "spring"; //읽기 전용 속성이므로 'name'에 할당할 수 없습니다.ts(2540)

 

🟢 Type Assertions (타입 단언)

타입 단언은 타입스트립트가 타입 추론을 통해 판단할 수 있는 타입의 범주를 넘는 경우, 더 이상 추론하지 않도록 지시할 수 있습니다.

즉, 타입스트립트는 모르지만 우리가 타입에 대한 정보를 알고 있는 상황을 의미합니다.

 

isNumber는 boolean이며, 숫자 여부를 판단하는 값임을 우리는 추론할 수 있습니다.

하지만 타입스크립트는 isNumber만으로는 추론할 수 없기 때문에 에러가 발생됩니다.

function assertionFunc(val: string | number, isNumber: boolean) {
  //... logics
  if (isNumber) {
    val.toFixed(2); 
    //'string | number' 형식에 'toFixed' 속성이 없습니다.
    //'string' 형식에 'toFixed' 속성이 없습니다.ts(2339)
  }
}

두가지 방식으로 타입 선언을 할 수 있습니다.

변수 as 타입 (as - )

<타입>변수 (angle-bracket)

 

다만, 꺽쇠 괄호(<>)를 이용하면 JSX를 사용하는 경우 특정 구문 파싱에서 문제가 발생할 수 있으며, .tsx 파일에서는 동작하지 않습니다.

function assertionFunc(val: string | number, isnumber: boolean) {
  //... logics
  if (isnumber) {
    (val as number).toFixed(2);
  }

  if (isnumber) {
    (<number>val).toFixed(2);
  }
}

 

또한, 타입 단언은 불가능한 강제 타입 변환을 방지합니다.

 

🟢 Literal Types

 리터럴 타입은 집합 타입보다 구체적인 하위 타입입니다.

타입스크립트는 문자열과 숫자 두 가지 리터럴 타입이 있으며, 문자열이나 숫자에 정확한 값을 지정할 수 있습니다.

changingString은 변경될 수 있으므로 컴파일러는 문자열이라고 선언할 것입니다.

constantString은 문자열이 아닌 "Hello world"로 타입을 정합니다.

let changingString = 'Hello World';
changingString = 'Ola Mundo';
changingString;/* let changingString: string */

const constantString = 'Hello World';
constantString;/* const constantString: 'Hello World' */

 

리터럴 타입과 유니온 타입을 조합하면 유용하게 사용할 수 있습니다.

허용된 문자열이 아닌 다른 문자열을 사용하게 되면 오류가 발생됩니다.

type Alignment = "left" | "right" | "center";

function printText(s: string, alignment: Alignment) {
  console.log(`string is ${s}.`);
  console.log(`alignment is ${alignment}.`);
}
printText("Hello, world", "left");
printText("Good day, mate", "centre");
//'"centre"' 형식의 인수는 'Alignment' 형식의 매개 변수에 할당될 수 없습니다.ts(2345)

 

숫자 타입뿐만 아니라 다른 타입들과 조합하여 사용 가능합니다.

interface Options {
  width: number;
}
function configure(x: Options | "auto") {
  console.log(x);
}
configure({ width: 100 });
configure("auto");
configure("automatic");
//'"automatic"' 형식의 인수는 'Options | "auto"' 형식의 매개 변수에 할당될 수 없습니다.ts(2345)

 

🟢 null and undefined

값이 비어있거나, 초기화되지 않는 값을 표현하는 원시 값을 의미하며, 각각 자신의 타입 이름으로 사용할 수 있습니다.

let u: undefined = undefined;
let n: null = null;

 

strictNullChecks의 옵션에 따라 nullundefined는 오직 any와 각자 자신들 타입에만 할당 가능합니다.

{
  "compilerOptions": {
    "strict": true,
    "strictNullChecks": true // true or false
  },
  "exclude": ["node_modules"]
}

 

다만, "strictNullChecks": true이어도 void에는 undefined를 할당할 수 있습니다.

let vo: void = undefined;
//'undefined' 형식은 'number' 형식에 할당할 수 없습니다.ts(2322)
let num: number = undefined;
//'null' 형식은 'string' 형식에 할당할 수 없습니다.ts(2322)
let str: string = null;

 

🟢 Non-null Assertion Operator: Postfix ! (Non-null 단언 연산자)

!를 어떤 표현식 뒤에 사용하며, 피연산자가 null, undefined값이 아님을 단언할 수 있습니다.

null에 대한 처리는 다양하게 해결할 수 있지만, Non-null 단언 연산자를 이용해 간단하게 정리할 수 있습니다.

function liveDangerously(x?: number | null | undefined) {
  //if statement
  if (x) {
    console.log(x.toFixed(2));
  }

  // Type assertion
  console.log((x as number).toFixed(2));

  // Non-null assertion operator
  console.log(x!.toFixed(2));
}

 

🟢 Enums (열거형)

enums은 타입스크립트가 자바스크립트에 추가한 기능입니다.

숫자 혹은 문자열 값 집합에 이름을 부여할 수 있는 타입으로 일정한 범위로 정해져 있는 값이 있는 경우 활용할 수 있습니다.

 

기본적으로 값은 0부터 시작하여 1씩 증가합니다.

enum color {
  Red, //(enum member) color.Red = 0
  Blue,
  Green,
  Yellow,
  Black,
  White, //(enum member) color.White = 5
}

 

수동으로 값을 변경 가능하고 변경된 값 이후부터 다시 1씩 증가합니다.

enum color {
  Red, //(enum member) color.Red = 0
  Blue = 22,
  Green, //(enum member) color.Green = 23
  Yellow,
  Black,
  White, //(enum member) color.White = 26
}

 

Enum 타입의 특징 중 하나는 역방향 매핑을 지원합니다.

즉, 열거된 멤버에 대해 값으로 접근 또는 멤버로 값을 접근할 수가 있습니다.

enum color {
  Red, //(enum member) color.Red = 0
  Blue = 22,
  Green, //(enum member) color.Green = 23
  Yellow,
  Black,
  White, //(enum member) color.White = 26
}

console.log(color.Red); // 0
console.log(color[26]); // 'white'
console.log(color);
/*
{
  '0': 'Red',
  '22': 'Blue',
  '23': 'Green',
  '24': 'Yellow',
  '25': 'Black',
  '26': 'White',
  Red: 0,
  Blue: 22,
  Green: 23,
  Yellow: 24,
  Black: 25,
  White: 26
}
*/

 

 

 

🟢 Symbol (심벌)

자바스크립트는 5개의 원시 타입 : String, Number, Boolean, null, undefined을 가지고 있습니다.

Symbol은 ES6에서 새롭게 추가된 6번째 원시 타입으로 변경 불가능한 값입니다.

 

symbol 함수에 문자열 인자를 전달할 수 있으며, 생성에 어떠한 영향을 주지 않고 디버깅 용도로만 사용됩니다.

let firstSymbol = Symbol("first");
let secondSymbol = Symbol();

console.log(firstSymbol === secondSymbol); //false
console.log(firstSymbol === Symbol("first")); //false

 

symbol은 객체의 key로 사용될 수 있습니다.

한 가지 특이한 점은 symbol로 생성된 key에는 Object.keys, for in과 같은 메서드에서 접근하지 않습니다.

symbol과 함께 추가된 getOwnPropertySymbols()를 통해서 key에 접근할 수 있습니다.

const k2 = Symbol("k2");
const k3 = Symbol("k3");

const obj = {
  k1: "key1",
  [k2]: "key2",
  [k3]: "key3",
};

console.log(Object.keys(obj)); // [ 'k1' ]
console.log(Object.getOwnPropertySymbols(obj)[0] === k2); // true

내장된 Symbol은 Well-known Symbols에 정의되어 있습니다.

 

 

 

 

참고

타입스크립트 원본

타입스크립트 한국어 번역본

한눈에 보는 타입스크립트

반응형

'Programming > TypeScript' 카테고리의 다른 글

TypeScript Handbook 정리1 - The Basics  (0) 2021.09.13