타입 기본
기본 타입 훑어보기
원시 타입
- 불변하는 타입
- 객체가 아닌 값들
- 원시 타입은 타입스크립트가 자동으로 타입 추론을 하기 때문에 생략해도 무방하다!
const str: string = 'STRING'
const num: number = 123
const bool: boolean = true
객체 타입
- 객체 전체의 타입을 지정 가능
- 객체 자체의 타입을 지정하면 any와 다를게 없다
/**
* Object Type
*/
// object는 any와 다른게 없는 상황
const obj: object = {
str: "str",
num: 123,
child: {
str: "str",
num: 123,
},
};
// obj.num - object literal
const obj2: {
str: string;
num: number;
child: {
str: string;
num: number;
};
} = {
str: "str",
num: 123,
child: {
str: "str",
num: 123,
},
};
함수 타입
- 매개 변수의 타입(Parameter)
- 반환값의 타입(Return)
- Return 값은 타입 추론이 가능하기 때문에 반드시 달아줄 필요는 없다
/**
* Function Type
*/
function func(num: number, str: string): string {
return num + str
}
func(123, 'str')
function func2(num1: number, num2: string): number {
return num1 + Number(num2) //자동 형변환 방지
}
func2(123, '123')
function func3(num1: number, num2: string): void {
console.log(num1 + num2)
}
func3(123, '123')
//! 반환형은 타입 추론이 가능하기 때문에 무조건 달아줄 필요는 없다!
const func4 = (str1: string, str2: string): string => {
return str1 + ' ' + str2
}
func4('hello', 'world')
const func5 = (obj: { str1: string, str2: string }) => {
return obj.str1 + ' ' + obj.str2
}
func5({ str1: 'hello', str2: 'world' })
배열 타입
- 배열 전체의 타입을 지정 가능
- 튜플이라는 별도의 형식도 존재!
/**
* Array Type
*/
const strArr: string[] = ['str', 'str2', 'str3']
const strArr2: Array<string> = ['str', 'str2', 'str3']
const numArr: Array<number> = [1, 2, 3]
const boolArr: boolean[] = [false, true, false, true]
strArr.push(1) //error!
numArr.push('str') //error!
boolArr.push(false)
// Tuple
const arr = ['str', 123, false]
튜플 타입
- 배열에서 길이와 index의 타입이 고정
- 여러 다른 타입으로 이루어진 배열을 안전하게 관리 가능
- 배열 타입의 길이를 조절 가능
/**
* Tuple Type
*/
const arr: string[] = ['A', 'B', 'C']
// 길이 고정
const tuple: [number, string] = [1, 'A']
// Union Type
const tuple0: (string | number)[] = [1, 'A']
const tuple2: [number, ...string[]] = [0, 'A', 'B']
undefined & null
- undefined으로 뭉뚱그려 처리하는 것 대신 void, never 등 더 세밀한 타입을 제공
- vanila JS와 마찬가지로 각각을 고유한 타입으로 인정한다.
- strictNullChecks가 핵심
- strictNullChecks: 개발자가 null이나 undefined 값을 참조하지 않도록 에러를 보여준다.
- 실제로 참고하지 않더라도 참고할 가능성이 있을 때도 컴파일 에러를 보여줘서 안전한 코딩이 가능하다
/**
* undefined & null
*/
//되도록 둘 중 하나만 사용하기!
const nu: null = null;
const un: undefined = undefined;
function sayHello(word: string) {
if (word === 'world') {
return 'hello' + word
}
return null
}
function log(message: string | number) {
console.log(message)
}
any
- 모든 값(타입)의 집합
- 사용하지 말자!!!(타입스크립트의 의미가 없어진다)
- noImplicitAny or strict 옵션 true 권장 - 자동으로 any 형 변환 되는 것을 막아준다
/**
* any
*/
function func(anyParam: any) {
anyParam.trim()
}
func([1,2,3])
unknown
- any 대신 새로 추가된 최상위 타입
- any처럼 모든 값을 허용하지만 상대적으로 엄격하다.
- 타입 추론 대상에서 제외되므로 개발자가 직접 명시해야 한다.
- assertion 혹은 Type guard와 함께 사용한다.
/**
* unknown
*
* 새로운 최상위 타입
* any처럼 모든 값을 허용하지만 상대적으로 엄격하다.
* TS에서 unknown으로 추론하는 경우는 없으니 개발자가 직접 명시해야함
* assertion 혹은 타입 가드와 함께 사용한다.
*/
let num: unknown = 99;
//타입 가드
if (typeof num === 'string') {
num.trim();
}
// (num as string).trim();
//// 모두 에러 발생 안함!
// function func(x: any) {
// let val1: any = x;
// let val2: unknown = x;
// let val3: string = x;
// let val4: boolean = x;
// let val5: number = x;
// let val6: string[] = x;
// let val7: {} = x;
// }
// // any와 unknown만 가능
// function func(x: unknown) {
// let val1: any = x;
// let val2: unknown = x;
// let val3: string = x; //err
// let val4: boolean = x; //err
// let val5: number = x; //err
// let val6: string[] = x; //err
// let val7: {} = x; //err
// }
void
- 함수의 반환이 없는 경우를 명시
- return이 없으면 자동으로 타입추론하므로 타입추론에 위임하자!
- 바닐라 JS에서는 undefined를 반환하지만 TS에서 void와 undefined는 같은 것이 아니다.
/**
* void
*/
//명시하지 않아도 void 반환 함수
function test() {
console.log("void fucntion");
}
클래스
- JavaScript에서는 ES2015의 새로운 문법으로 도입
- 객체 지향형 프로그래밍의 핵심
- TypeScript에서의 클래스 기능은 C#(MS사 개발)에서 유래된 것이 많다.
- 일부 기능(인터페이스 등)은 TS에서만 존재하는 고유 문법이기때문에 JS로 컴파일 후에는 사라진다.
생성자 & 인스턴스
/**
* Class
*/
class Person {
/**
* 필드
* - 일종의 속성
* - public으로 사용가능합니다.
*/
name: string;
age: number;
readonly location: string = "Korea";
/**
* 생성자
*
* - 초기화를 담당
*/
constructor(name: string, age: number) {
this.name = name
this.age = age
}
}
/**
* 인스턴스
*
* - 클래스에서 파생된 고유한 것
* - 실제로 생성된 후 메모리에 올라감
*/
const p1 = new Person('Jang', 99);
const p2 = new Person('Poco', 100);
console.log(p1)
console.log(p2)
메서드
- 객체(클래스)에 포함된 함수
/**
* method
*/
class Person {
name: string;
age: number;
readonly location: string = "Korea";
constructor(name: string, age: number) {
this.name = name
this.age = age
}
/**
* 메서드
*
* 객체(클래스)에서는 행동을 뜻한다.
*/
introduce(): string {
return `${this.name}의 나이는 ${this.age} 입니다.`
}
}
const p1 = new Person('Jang', 99);
const p2 = new Person('Poco', 100);
console.log(p1.introduce())
console.log(p2.introduce())
Getter & Setter
- 필드에 접근할 권한을 가진 제어자
- getter만 있고 setter가 없다면 속성은 자동으로 readonly가 된다.
- setter 매개변수의 타입이 없어도 getter의 반환 타입에서 추론한다.
- private 속성은 자식(.) 연산자로 접근할 수 없다.
/**
* Getter & Setter
*/
class Person {
name: string;
//프라이빗 변수는 보통 _를 붙인다
private _age: number;
constructor(name: string, age: number) {
this.name = name
this._age = age
}
get age() {
if (this._age === 0) {
return '설정되지 않았습니다.'
}
return `나이는 ${this._age}세로 추정됩니다.`
}
set age(age) {
// 타입 가드
if (typeof age === 'number') {
this._age = age
}
this._age = 0;
}
}
const p = new Person('Jang', 0)
console.log(p.age)
console.log(p.name)
extends
- 클래스를 상속 받을 수 있다
- 확장의 개념
/**
* extends
*/
class 기본 {
result() {
return 'Base'
}
}
class 파생 extends 기본 {
//overriding
result() {
return 'Derived'
}
}
const de = new 파생()
console.log(de.result())
super
- 상속 받는 클래스에서 부모 클래스의 요소 호출 시 사용
- 생성자에서 this 사용 전에 호출되어야 한다.
/**
* super
*/
class Animal {
name: string
constructor(name: string) {
this.name = name
}
sayName() {
return `동물의 이름은 ${this.name}`
}
}
class Person extends Animal {
constructor(name: string) {
super(name)
}
sayName() {
return `${super.sayName()} 사람의 이름은 ${this.name}`
}
}
class Jang extends Person {
}
const person = new Person('Jang')
console.log(person.sayName())
접근제어자
- 속성과 메서드에 접근을 제한할 수 있다
- 클래스 내부 구현 정보를 적당히 공개하여 일부분만 노출시킨다.
- API와 비슷한 흉내를 낼 수 있다
- 타입 시스템을 이용해 규칙을 강제할 수 있다
public | 어디서나 접근 가능(기본값) |
protected | 해당 클래스와 서브클래스에서만 접근 가능 |
private | 해당 클래스에서만 접근 가능 |
/**
* 접근제어자
*/
class Person {
public name: string
private age: number
protected gender: 'M' | 'F'
constructor(name: string, age: number, gender: 'M' | 'F') {
this.name = name
this.age = age
this.gender = gender
}
sayName() {
return `이름은 ${this.name} 입니다`
}
protected sayAge() {
return `나이는 ${this.age}`
}
private sayGender() {
return `성별 타입은 ${this.gender}`
}
}
class Me extends Person {
constructor(name: string, age: number, gender: 'M' | 'F') {
super(name, age, gender)
}
sayInfo() {
//sayGender 에러 발생
return `${super.sayGender()} ${super.sayAge()} ${super.sayName()}`
}
}
const p = new Person('jang', 99, 'M')
static
- 클래스의 속성과 메서드를 new로 인스턴스화 하지 않고 호출할 수 있다
- 접근 제어자를 활용할 수 있다
- 몇 가지 정적 이름을 사용할 수 없다
- 클래스는 그 자체로 new로 호출할 수 있는 함수이기 때문
- 예) function.name (불가능)
/**
* static
*/
class StaticClass {
private static type = 'Type'
static name = 'name' //name은 function의 빌트인 속성이라 사용 불가!
static getType() {
return StaticClass.type
}
}
// console.log(StaticClass.type)
console.log(StaticClass.getType())
readonly
- TS에만 존재
- 말 그대로 수정은 안 되고 읽기만 가능하다
/**
* readonly - TS에만 존재
*/
class Person {
name: string
readonly age: number
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
//error 발생!
setAge(newAge: number) {
this.age = newAge
}
}
const p = new Person('Jang', 99)
p.name = 'JJJ' //아무나 수정 가능!
p.age = 30 //error!
추상 클래스
- abstract를 선언한 클래스로, 직접 인스턴스화(new) 될 수 없는 클래스이다
- 일종의 클래스 설계도
- 직접 인스턴스화 될 수는 없지만 extends 후 파생된 클래스를 인스턴스화 하도록 유도한다.
- 추상 클래스는 구현된 메서드를 포함시킬 수 있다
- abstract를 선언한 메서드는 파생된 클래스에서 메서드를 반드시 구현해야한다.
/**
* 추상 클래스
*/
abstract class Animal {
// 선언된 메서드 - 반드시 구현!
abstract hello(): string
// 구현된 메서드
run() {
return this.hello() + ' run'
}
}
// 직접 인스턴스가 될 수 없다.
// const animal = new Animal()
class Person extends Animal {
hello() {
return 'Person'
}
}
class Dog extends Animal {
hello() {
return 'Dog'
}
}
const person = new Person()
const dog = new Dog()
console.log(person.hello())
console.log(dog.hello())
Pararmeter Properties
- 클래스 생성과 동시에 생성자 선언
- this.~ 를 이용한 타입 초기화를 생략할 수 있다
/**
* Parameter Properties
*/
class Person {
//타입 정하면서 동시에 생성자 선언 + this.~ 생략가능!
constructor(
public name: string,
private age: number,
protected gender: 'M' | 'F'
) { //this.name = name 생략 가능
}
...
}
Method Overriding
상속 받은 메서드 덮어 쓰기
/**
* 메서드 오버라이딩
*/
class Animal {
run() {
return 'Animal이 달리다'
}
}
class Dog extends Animal {
run() {
return 'Dog가 달리다'
}
}
class Person extends Animal {
run() {
return 'Person이 달리다'
}
}
const a = new Animal()
const p = new Person()
const d = new Dog()
console.log(a.run())
console.log(p.run())
console.log(d.run())
그래도 이전에 JAVA와 C++을 한 덕분인지 이해하기 쉬웠다! JavaScript를 열심히 공부한 보람이 있다ㅎㅎㅎ
'Dev > JS Family, HTML, CSS' 카테고리의 다른 글
[TypeScript] 타입스크립트 입문 (4) - 제네릭, 고급 타입 다루기 (0) | 2022.09.14 |
---|---|
[TypeScript] 타입스크립트 입문(3) - 인터페이스, 타입 가드, 열거형, 유니온 타입 (0) | 2022.09.12 |
[TypeScript] 타입스크립트 입문(1) (2) | 2022.09.04 |
[React] 일주일만에 리액트 정복하기! (2) (0) | 2022.08.03 |
[React] 일주일만에 리액트 정복하기! (1) (1) | 2022.08.02 |