[TypeScript] TypeScript 기초
타입스크립트(TypeScript) 기초
타입스크립트(TypeScript) 기초
목차
기본 타입
/**
* function
*/
function add(num1: number, num2: number) {
console.log(1 + 2);
}
// add(1, 2)
function showItems(arr: number[]) {
arr.forEach((item) => {
console.log(item);
})
}
// showItems([1, 2, 3]);
/**
* TypeScript Type
* boolean, string, number, string[], number[], Array<string>, Array<number>
* void, never, enum, null, undefined
*/
let gender: boolean = true;
let car: string = 'bmw';
let age: number = 30;
let arr1: number[] = [1, 2, 3];
let arr2: Array<number> = [1, 2, 3];
let arr3: string[] = ['a', 'b', 'c'];
let arr4: Array<string> = ['a', 'b', 'c'];
let tuples: [string, number];
tuples = ['a', 1];
// tuples[0].toUpperCase(); // O
// tuples[1].toUpperCase(); // X
// void : 반환하지 않을 때
function sayHello(): void {
console.log("Hello");
//return 'Hi';
}
// sayHello();
// never : 끝나지 않을 때
function showError(): never {
throw new Error();
}
//showError();
function inLoop(): never {
while (true) {
// do Something..
}
}
// enum : 비슷한 값들끼리 묶어줌
enum OsNum {
Window,
Ios = 10,
Android
}
// console.log(OsNum[10]);
// console.log(OsNum['Ios']);
enum OsString {
Window = 'win',
Ios = 'ios',
Android = 'and'
}
let myOs: OsString; // 선언
myOs = OsString.Ios;
console.log(myOs);
// null, undefined
let isNull: null = null;
let isUndefined: undefined = undefined;
인터페이스(interface)
/**
* interface
*/
// user 객체 생성 // 객체는 object 타입으로 정의할 수 있음
let user: object;
user = {
name: 'gangpro',
age: 30
}
// console.log(user.name); // error
// console.log(user.age); // error
// 프로퍼티를 정의해서 객체로 표현할 때는 interface를 사용한다.
type Score = 'A' | 'B' | 'C' | 'F';
interface User1 {
name: string;
age: number;
gender?: string; // ? : optional
readonly birthYear: number; // readonly : 읽기전용
// grade1? : string,
// grade2? : string,
// grade3? : string,
// grade4? : string,
// [grade: number]: string,
[grade: number]: Score, // 문자열 리터럴 타입
}
let user1: User1 = {
name: 'gangpro',
age: 30,
birthYear: 2000, // interface에 readonly로 정의했기 때문에 생성할 때만 할당 가능하고 이후 수정 불가능
1: 'A',
2: 'B',
// 3: 'D', // error : Socre 타입에 D는 없기 때문에
}
// user1.age = 20;
// user1.gender = 'male'; // error : interface에 정의되어 있지 않기 때문에 // interface에 옵셔널하게 처리 가능
// user1.birthYear = 2002; // error : interface에 readonly로 정의했기 때문에 수정 불가능
/**
* interface function
*/
interface Add {
(num1: number, num2: number): number;
}
const add: Add = function (x, y) {
return x + y;
}
// console.log(add(1, 2));
interface IsAdult {
(age: number): boolean;
}
const sungin: IsAdult = (age) => {
return age > 19;
}
// console.log(sungin(20));
/**
* interface class : implement 키워드
*/
interface Car {
color: string;
wheels: number;
start(): void;
}
class Bmw implements Car {
color;
constructor(c: string) {
this.color = c;
}
wheels = 4;
start() {
console.log('go..');
}
}
const carB = new Bmw('green');
console.log(carB);
carB.start();
/**
* interface class : extends 키워드 : 한개의 경우
*/
interface Kia extends Car {
door: number;
stop(): void;
}
const carK: Kia = {
color: 'red',
wheels: 4,
start() {
console.log('start KIA');
},
door: 6,
stop() {
console.log('stop KIA');
}
}
/**
* interface class : extends 키워드 : 여러개의 경우
*/
interface Truck {
color: string;
wheels: number;
start(): void;
}
interface Toy {
name: string;
}
interface ToyTruck extends Truck, Toy {
price: number;
}
함수(function)
/**
* function
*/
function add1(num1: number, num2: number): number {
return num1 + num2;
}
function add2(num1: number, num2: number): void {
console.log(num1 + num2);
}
function isAdult(age: number): boolean {
return age > 19;
}
// 선택적 파라미터
function hello1(name?: string) {
return `Hello ${name || 'world'}`;
}
console.log(hello1());
function hello2(name = 'HI') {
return `Hello & ${name}`;
}
console.log(hello2());
// 선택적 파라미터는 앞에 쓸 수 없다.
function hello3(age?: number, name: string): string {
// function hello3(age?: number, name: string): string {
if(age !== undefined) {
return `Hello ${name}. You are ${age}.`;
}
else {
return `Hello ${name}`;
}
}
// 선택적 파라미터는 앞에 쓸 수 없다. 굳이 쓰려면 아래 처럼..
function hello4(age: number | undefined, name: string): string {
// function hello3(age?: number, name: string): string {
if(age !== undefined) {
return `Hello ${name}. You are ${age}.`;
}
else {
return `Hello ${name}`;
}
}
//
function addAll(...nums: number[]) {
return nums.reduce((result, num) => result + num, 0)
}
console.log(addAll(1, 2, 3));
console.log(addAll(1,2,3,4,5,6,7,8,9,10));
/**
* this
*/
interface User {
name: string
}
const Kang: User = { name: 'KANG' };
function showName(this: User) {
console.log(this.name);
}
const showMe = showName.bind(Kang);
showMe(); // KANG
function showName2(this: User, age: number, gender: 'M' | 'F') {
console.log(this.name, age, gender);
}
const showMe2 = showName2.bind(Kang);
showMe2(30, 'M'); // KANG, 30, 'M'
/**
* overloading
*/
interface User2 {
name: string,
age: number
}
function join(name: string, age: string): string; // age 가 string 일 때 string 반환
function join(name: string, age: number): User2; // age 가 number 일 때 User2 반환
function join(name: string, age: number | string): User2 | string {
if(typeof age === 'number') {
return {
name,
age
}
}
else {
return `나이는 숫자로 입력해주세요.`;
}
}
const kang: User2 = join('KANG', 30);
const sam: string = join('sam', '30');
리터럴 타입(literal types)
/**
* literal Types
*/
const userName1 = 'Bob'; // const userName1: 'Bob'
let userName2 = 'Tom'; // let userName2: string
type Job = 'developer' | 'designer' | 'teacher';
interface User {
name: string;
job: Job;
}
const user: User = {
name: 'KANG',
// job: 'student' // error
job: 'developer'
}
유니온 타입(union types)
or 의미
/**
* union Types
*/
interface Car {
name: 'car';
color: string;
start(): void;
}
interface Mobile {
name: 'mobile';
color: string;
call(): void;
}
function getGift(gift: Car | Mobile) {
console.log(gift.color);
// gift.start(); // error
if(gift.name === 'car') {
gift.start();
}
else if(gift.name === 'mobile') {
gift.call();
}
}
교차 타입(intersection types)
and 의미
/**
* intersection Types
*/
interface Car {
name: string;
start(): void;
}
interface Toy {
name: string;
color: string;
price: number;
}
const toyCar: Toy & Car = {
name: '타요',
start() {},
color: 'red',
price: 1000
}
클래스(class)
/**
* class
*/
class Car {
color: string; // 멤버 변수(member variable) : 메소드 밖에서 선언된 변수 // 메소드 안에서 선언된 변수는 지역 변수(local variable)
constructor(color: string) {
this.color = color;
}
start() {
console.log('start');
}
}
const bmw = new Car('red');
/**
* class
*/
class Car {
// public
constructor(public color: string) {
this.color = color;
}
start() {
console.log('start');
}
}
const bmw = new Car('red');
접근 제한자(Access modifiers) : public
자식 클래스, 클래스 인스턴스 모두 접근 가능
class Car {
public name: string = 'Car'; //= name: string = 'Car';
color: string;
constructor(color: string) {
this.color = color;
}
start() {
console.log('start >>>');
}
}
class Bmw extends Car {
constructor(color: string) {
super(color);
}
showName() {
console.log(super.name);
}
}
const whosCar = new Bmw('block');
// public으로 선언한 name을 클래스 인스턴스로 접근 가능
console.log(whosCar.name); // ok
접근 제한자(Access modifiers) : private 1
해당 클래스 내부에서만 접근 가능
class Car {
// name이 private이기 때문에 Car 클래스 내부에서만 사용가능하므로 Bmw 클래스 > showName()에서 error
//= #name: string = 'Car';
private name: string = 'Car';
color: string;
constructor(color: string) {
this.color = color;
}
start() {
console.log('start >>>');
console.log(this.name);
// console.log(this.#name); // Car 클래스에서 #name: string = 'Car';를 사용한 경우에 this.#name으로 써야한다.
}
}
class Bmw extends Car {
constructor(color: string) {
super(color);
}
showName() {
console.log(super.name); // error
}
}
접근 제한자(Access modifiers) : private 2
해당 클래스 내부에서만 접근 가능
class Car {
// name이 private이기 때문에 Car 클래스 내부에서만 사용가능하므로 Bmw 클래스 > showName()에서 error
#name: string = 'Car';
color: string;
constructor(color: string) {
this.color = color;
}
start() {
console.log('start >>>');
console.log(this.#name); // Car 클래스에서 #name: string = 'Car';를 사용한 경우에 this.#name으로 써야한다.
}
}
class Bmw extends Car {
constructor(color: string) {
super(color);
}
showName() {
console.log(super.name); // error
}
}
접근 제한자(Access modifiers) : protected
자식 클래스에서 접근 가능
class Car {
protected name: string = 'Car';
color: string;
constructor(color: string) {
this.color = color;
}
start() {
console.log('start >>>');
console.log(this.name); // 자식 클래스에서 참조 가능
}
}
class Bmw extends Car {
constructor(color: string) {
super(color);
}
showName() {
console.log(super.name); // public처럼 protected도 자식 클래스에서 접근 가능
}
}
const whosCar = new Bmw('block');
// protected로 선언한 name은 자식 클래스에서 참조할 수 있으나
// class 인스턴스로 참조할 수 없음
console.log(whosCar.name); // error
public & readonly 1
class Car {
public name: string = 'Car';
color: string;
constructor(color: string) {
this.color = color;
}
start() {
console.log('start >>>');
console.log(this.name);
}
}
class Bmw extends Car {
constructor(color: string) {
super(color);
}
showName() {
console.log(super.name);
}
}
const whosCar = new Bmw('block');
console.log(whosCar.name); // Car
whosCar.name = 'Truck';
console.log(whosCar.name); // Truck
public & readonly 2
class Car {
readonly name: string = 'Car';
color: string;
constructor(color: string) {
this.color = color;
}
start() {
console.log('start >>>');
console.log(this.name);
}
}
class Bmw extends Car {
constructor(color: string) {
super(color);
}
showName() {
console.log(super.name);
}
}
const whosCar = new Bmw('block');
console.log(whosCar.name); // Car
whosCar.name = 'Truck'; // error
public & readonly 3
class Car {
readonly name: string = 'Car';
color: string;
constructor(color: string, name: string) {
this.color = color;
this.name = name;
}
start() {
console.log('start >>>');
console.log(this.name);
}
}
class Bmw extends Car {
constructor(color: string, name: string) {
super(color, name);
}
showName() {
console.log(super.name);
}
}
const whosCar = new Bmw('block', 'Truck');
console.log(whosCar); // Car
static
static을 쓰면 정적 멤버 변수를 만들 수 있다.
class Car {
readonly name: string = 'Car';
color: string;
static wheels = 4;
constructor(color: string, name: string) {
this.color = color;
this.name = name;
}
start() {
console.log('start >>>');
console.log(this.name);
//console.log(this.wheels); // error : static으로 선언된 멤버 변수나, 정적 멤버 변수는 this가 아니라 클래스 명으로 사용해야 한다.
console.log(Car.wheels); // ok
}
}
class Bmw extends Car {
constructor(color: string, name: string) {
super(color, name);
}
showName() {
console.log(super.name);
}
}
console.log(Car.wheels);
추상 class 1
abstract class Car {
color: string;
constructor(color: string) {
this.color = color;
}
start() {
console.log('start >>>');
}
}
const car = new Car('red'); // error : 추상 class는 new로 객체를 만들 수 없다. 아래처럼 상속을 통해서만 사용 가능.
class Bmw extends Car {
constructor(color: string) {
super(color);
}
}
추상 class 2
abstract class Car {
color: string;
constructor(color: string) {
this.color = color;
}
start() {
console.log('start >>>');
}
abstract doSomething(): void;
}
// error : Car 추상 class 내부에 추상 method는 반드시 상속받은 곳에서 반드시 구현해줘야함.
// 그래서 구체적인 기능은 상속받은 곳에서 따로 진행
class Bmw extends Car {
constructor(color: string) {
super(color);
}
doSomething() {
alert('OK');
}
}
제네릭(generics)
// 제네릭을 이용하면 class, function, interface를
// 다양한 type으로 재사용 할 수 있다.
// 선언 할 때는 타입 파라미터만 적어주고 생성하는 시기에 타입을 정해준다.
function getSize(arr: number[] | string[] | boolean[]): number {
return arr.length;
}
const arr1 = [1, 2, 3];
console.log(getSize(arr1)); // 3
const arr2 = ['a', 'b', 'c'];
console.log(getSize(arr2));
const arr3 = [true, true, false];
console.log(getSize(arr3));
function에서 generics
// 타입이 증가할 때마다 getSize에 union 타입을 계속 적는 것 보다는 generic을 사용하는게 좋음.
// <T> 타입 파라미터라고 한다. // X, A, ... 어떤걸 써도 상관은 없음.
function getSize<T>(arr: T[]): number {
return arr.length;
}
const arr1 = [1, 2, 3];
getSize<number>(arr1); //= function getSize<number>(arr: number[]): number { ... }
const arr2 = ['a', 'b', 'c'];
getSize<string>(arr2); //= function getSize<string>(arr: string[]): number { ... }
const arr3 = [true, true, false];
getSize(arr3); //= function getSize<boolean>(arr: boolean[]): number { ... }
const arr4 = [1, 2, 3];
getSize<number | string>(arr4); //= function getSize<number | string>(arr: (number | string)[]): number { ... }
interface 에서 generics 1
// interface generic ex
interface Mobile<T> {
name: string;
price: number;
// option: any;
option: T;
}
// object 생성
//= const m1: Mobile<object> = {
const m1: Mobile<{color: string, coupon: boolean}> = {
name: 'iPhone13',
price: 100,
option: {
color: 'black',
coupon: false
}
}
const m2: Mobile<string> = {
name: 'iPhone14',
price: 130,
option: 'new one'
}
interface 에서 generics 2
interface User {
name: string;
age: number;
}
interface Car {
name: string;
color: string;
}
interface Book {
price: number;
}
const user: User = { name: 'KANG', age: 30 };
const car: Car = { name: 'volvo', color: 'black' };
const book: Book = { price: 1000 };
function showName<T extends { name: string }>(data: T): string {
return data.name;
}
showName(user);
showName(car);
showName(book); // error : Book interface 안에 name 없기 때문에
유틸리티 타입(utility types)
keyof
interface User {
id: number;
name: string;
age: number;
gender: 'M' | 'F';
}
// keyof 키워드를 사용하면
// User interface에서 키 값들을 union 형태로 받을 수 있다.
type UserKey = keyof User; //= 'id' | 'name' | 'age' | 'gender';
const userkey1: UserKey = ''; // error
const userkey2: UserKey = 'id'; // ok
const userkey3: UserKey = 'mobile'; // error
Partial<T>
// Partial<T>
// 객체 속성(property)를 모두 optional로 바꿔 줌
// 그래서 일부만 사용 가능함.
interface User {
id: number;
name: string;
age: number;
gender: 'M' | 'F';
}
// error
let admin1: User = {
id: 1,
name: 'KANG'
}
// ok
let admin2: Partial<User> = {
id: 1,
name: 'KANG',
// job: 'developer' // error : User에 없는 property를 사용하면 에러
}
//= Partial<User>
// interface User {
// id?: number;
// name?: string;
// age?: number;
// gender?: 'M' | 'F';
// }
Required<T>
// Partial<T>의 반대 Required<T>
// Required<T>
// 객체 속성(property)를 모두 필수로 바꿔 줌
interface User {
id: number;
name: string;
age?: number;
}
// error : age? 가 필수 property가 되어 버림
let admin1: Required<User> = {
id: 1,
name: 'KANG'
}
// ok
let admin2: Required<User> = {
id: 1,
name: 'KANG',
age: 30
}
Readonly<T>
// Readonly<T>
// 읽기 전용으로 바꿔 줌
interface User {
id: number;
name: string;
age?: number;
}
let admin1: User = {
id: 1,
name: 'KANG'
}
admin1.id = 0; // ok
interface User {
id: number;
name: string;
age?: number;
}
let admin1: Readonly<User> = {
id: 1,
name: 'KANG'
}
admin1.id = 0; // error : 처음에 할당만 가능하고 수정은 불가능하게 됨.
Record<K, T>
1
// Record<K, T>
// K : keys
// T : type
interface Score {
'1': 'A' | 'B' | 'C' | 'D';
'2': 'A' | 'B' | 'C' | 'D';
'3': 'A' | 'B' | 'C' | 'D';
'4': 'A' | 'B' | 'C' | 'D';
}
const score: Score = {
1: 'A',
2: 'B',
3: 'C',
4: 'D'
}
const score: Record<'1' | '2' | '3' | '4', 'A' | 'B' | 'C' | 'D'> = {
1: 'A',
2: 'B',
3: 'C',
4: 'D'
}
type Grade = '1' | '2' | '3' | '4';
type Score = 'A' | 'B' | 'C' | 'D';
const score: Record<Grade, Score> = {
1: 'A',
2: 'B',
3: 'C',
4: 'D'
}
Record<K, T>
2
// Record<K, T>
// K : keys
// T : type
interface User {
id: number;
name: string;
age: number;
}
function isValid(user: User) {
const result: Record<keyof User, boolean> = {
id: user.id > 0,
name: user.name !== '',
age: user.age > 0
};
return result;
}
Pick<T, K>
// Pick<T, K>
// T : type
// K : keys
interface User {
id: number;
name: string;
age: number;
gender: 'M' | 'F';
}
const admin: Pick<User, 'id' | 'name'> = {
id: 0,
name: 'KANG'
}
Omit<T, K>
// Pick<T, K>의 반대 Omit<T, K>
// Omit<T, K>
// T : type
// K : keys
interface User {
id: number;
name: string;
age: number;
gender: 'M' | 'F';
}
const admin: Omit<User, 'age' | 'gender'> = {
id: 0,
name: 'KANG'
}
Exclude<T1, T2>
// Omit<T, K>와 비슷한 Exclude<T1, T2>
// Exclude<T1, T2>
// T : type
// T1에서 T2를 제외하고 사용하는 방법
// Omit과 다른점은 Omit은 properties를 제거하는 방법이고, Exclude는 type으로 제거하는 방법
type T1 = string | number | boolean;
type T2 = Exclude<T1, number>; //= T2 = string
type T3 = Exclude<T1, number | string>; //= T3 = boolean
NonNullable<Type>
// NonNullable<Type>
// null, undefiend를 제외한 타입을 생성
type T1 = string | null | undefined | void;
type T2 = NonNullable<T1>; //= type T2 = string | void