(TS) Basic Grammar Summary

Mirrer·2022년 12월 29일
0

TypeScript

목록 보기
14/14
post-thumbnail

Basic Type

TypeScript기존 JavaScript Type과 더불어 다음과 같은 추가 Type을 사용할 수 있다.


JavaScript Type

String : 문자열
Number : 숫자
Boolean : true / false
Array : 배열
Object : 객체
Null : 빈 값
Undefined : 정의되지 않은 값
symbol : 수정 불가능한 고유값

TypeScript Type

Tuple : 길이와 각 요소의 타입이 정해진 배열
Enum : 특정 값들의 집합
Any : 모든 타입
unknown : 확실하지 않은 타입
Void : return 값이 없는 함수 타입
Never : 항상 오류를 발생시키거나, return 값이 없는 함수 타입


Type Annotation

TypeScript특정 변수나, 값의 Type을 지정하기 위해 콜론( : ) + 타입명을 사용한다.

Primitive Type

Primitive Type(String, Number, Boolean, Null, Undefined)은 다음과 같이 표기한다.

const str: string = 'hello world'; // 문자열
const num: number = 0; // 숫자
const bool: boolean = true; // boolean
const nl: null = null; // null
const uf: undefined = undefined; // undefined

Array Type

Arraytype[], 제네릭 표기법 (Array<type>)의 방법으로 표기할 수 있으며, Union( | )을 사용하면 Type을 추가할 수 있다.

const arr1: number[] = [1, 2, 3];
const arr2: string[] = ["1", "2", "3"];

const arr3: Array<number> = [1, 2, 3];
const arr4: Array<string> = ["1", "2", "3"];

const arr5: (number | string)[] = [1, '1', 2, '2'];
const arr6: Array<number | string> = [1, '1', 2, '2'];

Object Type

Objecttypeof 연산자가 object로 반환하는 모든 타입을 나타내며, 객체 각각의 타입을 개별적으로 표기한다.

const obj1: object = {};
const obj2: { name: string, price: number } = {
  name: 'apple',
  price: 100
};

Function Type

Function매개변수, return값의 Type을 표기한다.

function add(num1: number, num2: number): number {
	return a + b;
}

add(1, 2);

Tuple Type

Tuple은 길이가 가변적인 Array와는 달리 미리 요소의 갯수를 정하여 고정적인 배열을 표현한다.

그래서 미리 정해진 요소의 갯수만큼 타입 또한 미리 선언한다.

const tuple1: [string, number] = ['1', 1];
const tuple2: [string, number] = ['1', '1']; // Error

const tuple3: [string, number] = ['1', 1];
tuple3[1].length; // Error (tuple3[1]의 Type은 number)
tuple3[2] = "2"; // Error (정의되지 않은 인덱스)

Enum Type

EnumEnumerated Type(열거형)을 의미하며, 값들의 집합을 명명하고 이를 사용할 수 있게 한다.

일반적으로 사용하고 있는 열거자들은 주로 식별자이며 대표적으로 Boolean을 예로 들 수 있다.

기존 JavaScriptEnum을 제공하지 않아 상수들의 집합을 정의할 수 없었지만, TypeScript에서는 이를 해결하고자 Enum을 지원한다.

값은 기본적으로 0부터 시작하며, 이 후 1씩 증가한다.

enum obj { a, b, c };
console.log(obj);
// 0: "a"
// 1: "b"
// 2: "c"

다음과 같이 의도적으로 인덱스를 변경할 수도 있다.

enum obj { a = 1, b = 2, c = 3 };
const a: String = obj[1];

enum fruits { Apple, Banana, Grape }
const eat: fruits = fruits.Apple;

Any Type

Any모든 Type을 허용한다.

주로 Type 선언이 어려운 경우에 사용되며, Compile과정에서 Type을 검사하지 않아 에러 발생에 주의해야 한다.

let anything: any = 1;

any = 'Hello World';
console.log(anything); // Hello World

any = [1, 2, 3];
console.log(anything); // [1, 2, 3]

Void Type

Void는 변수에 undefined 또는 null만 할당할 수 있으며, 함수에서는 return값이 없는 경우 할당할 수 있다.

const n: void = undefined;

function sayHello(): void {
  console.log("Hello!!");
}
console.log(sayHello()); // undefined

Never Type

Never값의 공집합이며, 집합에 아무런 값이 존재하지 않기 때문에 Any 타입의 값을 포함한 어떠한 값도 가질 수 없다.

그래서 Never 타입은 때때로 점유할 수 없는, 혹은 바닥 타입이라고 불린다.

declare const any: any
const never: never = any // Any타입은 Never타입에 할당할 수 없다.

Union & Intersection

Union Type

Union집합의 합집합을 뜻하며, JavaScriptOR 연산자(||)와 같이 'A' 또는 'B'라는 의미의 타입으로 주로 여러 타입을 지정할 때 사용한다.

Union Type을 사용할 때는 '|'기호를 사용하여 타입을 열거한다.

let type = string | number; // type = string or type = number

Intersection Type

Intersection집합의 교집합을 뜻하며, JavaScriptAND 연산자(&&)와 같이 'A' 와 'B'라는 의미의 타입으로 지정한 여러 타입을 모두 만족하는 하나의 타입을 지정할 때 사용한다.

Intersection Type을 사용할 때는 '&'기호를 사용하여 타입을 열거한다.

type type1 = string;
type type2 = number;
type type3 = type1 & type2

Optional Parameter

Optional Parameter값의 존재 유무가 확실하지 않은 경우에 사용되며, '?'기호를 사용하여 필수 요소 유무를 제어할 수 있다.

function add(num1: number, num2?: number) {
	console.log(num1 + num2);
}

add(1, 2); // 3
add(1); // 1

Utility Type

TypeScript는 일반적인 타입 변환을 쉽게 하기 위해 전역적으로 사용할 수 있는 다양한 Utility Type을 제공한다.

대표적인 종류는 다음과 같으며, 공식 홈페이지를 통해 추가 Type을 확인할 수 있다.

Partial<T> : T의 프로퍼티를 선택적으로 구성
Readonly<T> : T의 프로퍼티를 읽기 전용으로 설정하여, 값을 재할당하는 경우 에러가 발생
Record<T, K> : 프로퍼티 키를 K, 값을 T로 하는 타입을 생성
Pick<T, K> : T 타입 중에서 K 프로퍼티만 지정하여 타입을 생성
Omit<T, K> : T 타입의 모든 프로퍼티 중 K를 제거하여 타입을 구성
Exclude<T, U> : 타입 T에서 U와 겹치는 타입을 제외한 타입을 구성
Extract<T, U> : 타입 T에서 U와 겹치는 타입만 포함하여 타입을 구성
NonNllable<T> : T 타입에서 nullundefined를 제외한 타입을 구성
Parameter<T> : 함수 타입 T의 매개변수의 타입들의 튜플로 타입을 구성
ConstructorParameters<T> : 클래스의 생성자를 비롯한 생성자 타입의 모든 매개변수 타입을 추출
ReturnType<T> : 함수 T가 반환한 타입으로 타입을 구성
Required<T> : 타입 T의 모든 프로퍼티가 필수로 설정된 타입을 구성


Class

Class객체 지향 프로그래밍(Object-oriented programming, OOP)에 사용되는 대표적인 문법으로 프로그래밍을 객체 단위로 나눠 작성하는 것이다.

객체 지향 프로그래밍의 장점은 다음과 같다.

  • 프로그램을 유연하고 변경이 용이하게 만든다.
  • 프로그램의 개발과 보수를 간편하게 만든다.
  • 직관적인 코드 분석을 가능하게 한다.
  • 객체 지향 프로그래밍의 특성: 강한 응집도, 약한 결합도를 지향

Class Grammar

Class필드(field), 생성자(constructor), 메소드(method)등의 요소로 구성되며, 해당 요소들을 묶어 Class멤버(member)라고 한다.

또한 이를 통해 생성된 객체는 인스턴스(instance)라고 부른다.

클래스 문법의 대표적인 특징은 다음과 같다.

  • 클래스를 생성하기 위해서는 class 키워드를 사용한다.
  • 클래스 내에서 클래스 멤버를 사용하기 위해서는 this 키워드를 사용한다.
  • 클래스 인스턴스를 생성하기 위해서는 new 키워드를 사용한다.

Property & Constructor

Class에서 정의된 변수는 속성(Property)이라 부르며, this 키워드를 통해 접근할 수 있다.

또한 Class 내부에서 Constructor 키워드를 사용하여 생성자(Constructor)를 정의할 수 있다.

class Apple {
  name: string; // Property
  
  constructor() { // Constructor
    this.name = 'apple'; // Constructor를 통해 Property 할당
  }
}

접근 제어자

접근 제어자는 Class의 접근을 제어하기 위해 사용되며, 각각의 접근제어자(public, protected, priavte)는 접근 범위 제한을 통해 나눠진다.

  • public : 모두 접근 가능하며, default
  • protected : 해당 클래스하위 클래스만 접근 가능
  • priavte : 클래스 외부에서 접근 불가

Readonly

ReadonlyClass member의 수정을 허용하지 않기 위해, 즉 읽기 전용으로 설정하기 위해 사용된다.

readonly 키워드를 사용하여 설정할 수 있으며 설정한 이후에는 값의 수정이 불가능하다.

class Apple {
  readonly name: string;
  
  constructor() {
    this.name = 'apple'; // Error
  }
}

Static

StaticClass의 특정 정적 멤버(메서드 또는 속성)를 전역적으로 공유하기 위해 사용되며, 이를 위해 해당 멤버에게 static 키워드를 사용한다.

그래서 Static을 사용하면 인스턴스를 생성하지 않고도 Class 멤버에 접근할 수 있다.

class Apple {
  static name: string = 'apple';  
}

console.log(Apple.name); // apple

Extends

객체 지향 프로그래밍은 상속이라는 개념을 이용하여 기존의 클래스를 확장하고 이를 상속받는 새로운 클래스를 생성할 수 있다.

Class의 상속은 extends 키워드를 사용하며, 상속을 받은 자식 클래스는 부모 클래스의 member뿐만 아니라 자신만의 member 또한 추가로 정의할 수 있다.

class Parent {
  	name: string = 'apple';  	
  	sayName() { console.log('apple') };
}

class Child extends Parent {
    // name: string = 'apple';
  	// sayName() { console.log('apple') };
    speakName() { console.log('banana') };
}

Getters & Setters

  • Getters

특정 속성에 접근할 때마다 그 값을 명시적인 함수 호출 없이 보여주고자할 때 getter를 사용하며, get 키워드를 사용하여 정의할 수 있다.

  • Setters

특정 속성 값이 변경되는 함수를 실행할 때 setter를 사용하며, set 키워드를 사용하여 정의할 수 있다.

class Shape {
  private name: string = 'apple';
  
  get sayName() {
    console.log(this.name);    
  }
  
  set setName(text) {    
    this.name = text;
  }
}

Abstract

Abstract추상 클래스를 의미하며 기존 Class와는 다르게 인스턴스화가 불가능하다.

그래서 추상 클래스를 사용하기 위해서는 상속과정이 반드시 필요하다.

추상 클래스나 추상 메소드를 정의할 때는 abstract 키워드를 사용하며 추상 클래스를 상속받은 클래스는 추상 클래스의 member를 구현해야 한다.

abstract class Parent {    
    abstract sayHello(): void;
}

class Child extends Parent {    
    sayHello() { console.log('Hello') }
}

Interface

Interface는 상호 간에 정의한 약속 혹은 규칙을 의미하며, interface 키워드를 사용하여 정의한다.

즉, Interface를 통해 값이 특정한 형태를 갖도록 정의, 제약할 수 있기 때문에 일반적으로 변수, 함수, 클래스의 타입을 체크하기 위해 사용된다.

또한, Interface는 프로퍼티와 메소드를 가질 수 있다는 점에서 Class와 역활이 비슷해보이지만 Interface는 직접 인스턴스를 생성할 수 없으며 모든 메소드가 추상 메소드이다.

interface Fruit {
  name: string;
  color: string;
  price: number;
}
const apple: Fruit = { name: 'apple', color: 'red', price: 100};

function sayFruit(f: Fruit): void {
    console.log(f.name);
  	console.log(f.color);
  	console.log(f.price);
}

Optional Interface

인터페이스에 정의되어 있는 속성 중 필수로 사용되지 않는, 즉 Optional한 값을 표현할 때는 '?'를 사용한다.

Optional이 포함된 Interface는 모든 요소를 필수로 사용하지 않아도 된다.

interface Fruit {
  name: string;
  color: string;
  price?: number;
}

const apple: Fruit = { name: 'apple', color: 'red' };

Interface Extends

Class와 마찬가지로 Interface 또한 상속받을 수 있다.

단, Interface간의 상속은 extends 키워드를 사용하지만 ClassInterface간의 상속은 implements 키워드를 사용한다.

interface Parent {};

interface Child1 extends Parent {};
class Child2 implements Parent {};

Abstract & Interface의 차이

추상(Abstract) 클래스는 앞서 설명했듯 상속(extends)을 통해 추상 메소드의 구현을 강제하기 때문에 선언과 구현이 모두 존재한다.

하지만 Interface는 이와 다르게 모든 구현에 대한 틀만 정해놓기 때문에 선언만 존재한다.

그래서 보통 추상 클래스는 프로그램의 전체 구조를 위해 사용되며, Interface는 기본적인 설계 용도로 사용된다.


Generic

Generic은 선언 시점이 아닌 생성 시점에 타입을 명시하여, 특정 자료형에 국한되지 않고 동적으로 여러 타입을 사용한다.

즉, 한번의 선언으로 다양한 타입을 재사용하여 하나의 타입만이 아닌 여러 타입을 사용할 수 있도록 한다.

Generic은 통상적으로 Type의 약자T를 통해 타입 변수를 선언하며, 이는 관용적으로 사용하는 값이기 때문에 다른 변수를 사용해도 무방하다.

function print<T>(arg: T): T { // T에는 동적으로 타입이 할당
	console.log(arg);  
}

print(1); // 1
print('Hello'); // Hello
print([1, 2, 3]); // [1, 2, 3]

Constraints

Generic에서는 제약조건을 통해 개발자가 원하지 않는 속성에 접근하는 것을 방지할 수 있다.

특정 타입만을 허용할 때는 extends 키워드를 사용하며, 두 객체를 비교할 때는 Keyof 키워드를 사용한다.

const print = <T extends number>(args: T): T => {
	console.log(args);
}

print(1); // 1
print('Hello'); // Error
function setProperty<T, K extends keyof T>(obj: T, key: K, value: T[K]): void {
    obj[key] = value;
}

function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
    return obj[key];
}

setProperty(person, 'name', 'Anna')

참고 자료

TypeScript: JavaScript With Syntax For Types.
React TypeScript Tutorial for Beginners - Codevolution
타입스크립트 입문 - 기초부터 실전까지 - 장기효

profile
memories Of A front-end web developer

0개의 댓글