4월 13일 (수) TypeScript

Southbig·2022년 4월 13일
0

TypeScript_기본타입

let age:number = 30;
let isAdult:boolean = true;
let a:number[] = [1, 2, 3];
let a2:array<number> = [1, 2, 3];
let week1:string[] = ['mon', 'true', 'wed'];
let week2:Array<string> = ['mon', 'tue', 'wed'];

튜플 (Tuple)

인텍스별로 타입이 다를 때 사용

let b:[string, number];

b = ['z', 1]; // 가능
b = [1, 'z']; // 불가능

b = b[0].toLowerCase(); // 가능
b = b[1].toLowerCase(); // 불가능

void, never

void
void는 함수에서 아무것도 반환하지 않을때 사용

function sayHello():void{
	console.log('hello');
}

never
never은 항상 에러를 반환하거나, 영원히 끝나지 않는 함수의 타입으로 사용

function showError():never{
	throw new Error();
}

function infLoop():never{
	while (true) {
    	// do something..
    }
}

enum

비슷한 값끼리 묶어져 있는 형태

enum Os {
	Window,
    Ios,
    Android
}

let myOs:Os;

myOs = Os.Window

특정값만 입력할 수 있게 강조하고 싶을때, 그 값들이 공통점이 있을 때 사용

null, undefined

let a:null = null;
let b:undefined = undifined;

인터페이스

let user:object;

user = {
	name : 'xx',
    age : 30
}

console.log(user.name) // 에러 발생
// 오브젝트에는 특정 속성 값에 대한 정보가 없기 때문에 에러 발생

프로퍼티를 정해서 객체를 표현 하고자 할 때는 인터페이스를 사용한다

interface User {
	name : string;
    age : number;
    gender? : string; // `?` 옵션처리(있어도 돼고 없어도 돼고)
}

let user : User = {
	name : 'xx',
    age : 30
}

user.age = 10;
user.gender = 'male'

console.log(user.age) 

read only 프로퍼티 (읽기전용)

값에 접근은 할 수 있지만 수정은 불가능 하다

interface User {
	name : string;
    age : number;
    gender? : string;
    readonly birthYear : number;
}

let user : User = {
	name : 'xx',
    age : 30,
    birthYear : 2000, // 읽기전용에서 최초생성할때만 할당이 가능하고 이후에는 수정안됨
}

user.age = 10;
user.gender = 'male'
user.birthYear = 1990; // 읽기전용으로 에러 발생

옵셔널 그 외의 방법

interface User {
	1? : string;
    2? : string;
    3? : string;
    4? : string;
}
interface User {
	[grade:nmber] : string
    // grade는 어떤 단어가 와도 상관없다 key 등 상관없다
}

문자열 리터럴 타입

type Score = 'A' | 'B' | 'C' | 'F';

interface User {
	[grade:nmber] : Score
    // 위와 같이 먼저 선언안 Score에 할당된 값 이외에는 사용 불가능
}

인터페이스로 함수 정의

interface Add {
	(인자값):리턴값
}
interface Add {
	(num1:number, num2:number):number;
}

const add : Add = function(x, y){
	return x + y
}

add(10, 20)
inferface IsAdult {
	(age:number):boolean;
}

const a:IsAdult = (age) => {
	return age > 19;
}

a(33) // true;

인터페이스로 클래스 정의

implements

interface Car {
	color: string;
    wheels: number;
    start(): void;
}

class Bmw implements Car {
	color = 'red';
    wheels = 4;
    start(){
    	console.log('go')
    }
}

constructor 사용

interface Car {
	color: string;
    wheels: number;
    start(): void;
}

class Bmw implements Car {
	color
    wheels = 4;
    
    constructor(c:string){
    	this.color = c;
    }
    
    start(){
    	console.log('go')
    }
}

const b = new Bmw('green');
console.log(b)
b.start();

확장

extends

interface Car {
	color: string;
    wheels: number;
    start(): void;
}

// extends 사용으로 기존에 가지고 있는 속성을 그대로 받게 된다
interface Benz extends Car {
	door: number;
    stop(): void;
    // 추가 할 수 있다
}

const benz : Benz = {
	door : 5,
    stop(){
    	console.log('stop');
    },
    // 기존에 설정되었던 값도 같이 써줘야 에러가 안남
    color : white,
    wheels: 4,
    start(){
    	console.log('go')
    }
}

동시확장

interface Car {
	color: string;
    wheels: number;
    start():void;
}

interface Toy {
	name:string;
}

interface ToyCar extends Car, Toy {
	price : number;
}

함수

각 매개변수의 타입을 입력, 괄호뒤에는 함수가 반환하는 타입을 입력

function add(num1: number, num2: number): number {
	return num1 + num2;
}
function add(num1: number, num2: number): void {
	// 아무것도 리턴하지 않으면 void 입력
    console.log(num1 + num2)
}
function isAdult(age: number): boolean {
	return age > 19;
}

인터페이스 처럼 함수에 매개변수도 옵션으로 지정 가능

선택적 매개변수

function hello(name?: string) {
	return `Hello, ${name || "world"}`
}

const result = hello();

// 매개변수에 옵션(?)을 지정 안해주면 에러 발생 (매개변수를 안넣어 줘서)

default 값 설정

function hello(name = 'world') {
	return `Hello, ${name}`; 
}

선택적 매개변수 사용법

function hello(name: string, age?: number): string {
	if (age !== undefined) {
    	return `Hello, ${name}. You are ${age}.`;
    } else {
    	return `Hello, ${name}`;
    }
}

console.log(hello('same'));
console.log(hello('same', 30));

// 만약 하기와 같이
function hello(age?: number, name: string): string
선택적 매개변수가 앞으로 오면 에러를 발생 시킨다
function hello(age?: number | undefined, name: string): string {
	if (age !== undefined) {
    	return `Hello, ${name}. You are ${age}.`;
    } else {
    	return `Hello, ${name}`;
    }
}

console.log(hello('same'));
console.log(hello(undefined, 'same'));

레스트 파라미터 (rest parameter)

// 에러
function add(...nums) {
	return nums.reduce((result, num) => result + num, 0);
}

add(1, 2, 3);
add(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

레스트 파라미터는 전달 받은 매개변수를 배열로 나타낼 수 있게 한다

즉,

function add(...nums: number[]) {
	return nums.reduce((result, num) => result + num, 0);
}

add(1, 2, 3);
add(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

this

interface User {
	name: string;
}

const Sam: User = {name:'Sam'}

function showName(){
	console.log(this.name) // 에러
}

const a = showName.bind(Sam);
a(); // 'Sam'

bind를 이용해서 this를 Sam 객체로 강제하고 있다

this type

interface User {
	name: string;
}

const Sam: User = {name:'Sam'}

function showName(this:User){ // this type 지정
	console.log(this.name)
}

this type, 매개변수가 있을 경우

interface User {
	name: string;
}

const Sam: User = {name:'Sam'}

function showName(this:User, age:number, gender: 'm' | 'f'){ // this type 지정
	console.log(this.name, age, gender)
}

const a = showName.bind(Sam);
a(30, 'm');

오버로드

interface User {
	name: string;
    age: number;
}
// age가 숫자면 User, string 이면 "나이는 숫자로 입력해주세요." 반환
function join(name: string, age: number | string): User | string {
	if (typeof age === "number") {
    	return {
        	name,
            age,
        };
    } else {
    	return "나이는 숫자로 입력해주세요."
    }
}

const sam: User = join("Sam", 30); // 에러
const jane: string = join("Jaene", "30"); // 에러

sam이나 jane은 user객체를 반환하는데 확신이 없는 거다, 두가지다 반환할 수도 있다고 생각하고있다

함수 오버로드는 전달받은 매개변수의 갯수나 타입에 따라 다른 동작을 하게 하는 것을 의미

interface User {
	name: string;
    age: number;
}

// 함수 오버로드
function join(name: string, age: string): string 
function join(name: string, age: number): User;
function join(name: string, age: number | string): User | string {
	if (typeof age === "number") {
    	return {
        	name,
            age,
        };
    } else {
    	return "나이는 숫자로 입력해주세요."
    }
}

const sam: User = join("Sam", 30); 
const jane: string = join("Jaene", "30"); 

동일한 함수지만 변수의 타입이나 갯수에 따라 다른방식으로 동작해야 된다면,
오버로드를 사용한다

리터럴, 유니온/교차 타입

리터럴 (Literal Types)

const user1 = "Bob"; // user1: "Bob"

let user2 = "Tom"; // user2: string
const user1 = "Bob"; // user1: "Bob"

let user2: string | number = "Tom"; // user2: string or number

user2 = 3; // 가능

정해진 string 값을 가진 것을 문자열 리터럴 타입이라고 한다

type Job = "police" | "developer" | "teacher"

interface User {
	name: string;
    job: job;
}

const user: User = {
	name: "Bob",
    job: "developer" // job은 위에 선언된 것만 사용가능하다
}

유니온 타입 (Union Types)

숫자형 interface

interface HighSchoolStudent {
	name: string;
    grade: 1 | 2 | 3;
}

|은 유니온 타입이라고 하는데, 두가지 이상 타입을 지정할 때 사용한다

interface Car {
	name: "car";
    color: string;
    start(): void;
}

interface Mobile {
	name: "mobile"
    color: string;
    call(): void;
}

function getGift(gift: Car | Moblie) {
	console.log(gift.color);
    gift.start(); // 에러 // Car에만 start 함수가 있기 때문에 에러가 발생
}
function getGift(gift: Car | Moblie) {
	console.log(gift.color);

// 동일한 이름의 속성을 정의하고 그것의 타입을 다르게 주므로서 두개의 인터페이스를 구분할 수 있다
// car type, mobile type
    if (gift.name === "car") {
    	gift.start();
    } else {
    	gift.call();
    }

동일한 속성의 타입을 다르게해서 구분할 수 있는 것을 식별가능한 유니온 타입이라고 한다

교차타입 (Intersection Types)

교차타입은 여러타입을 합쳐서 사용한다

유니온은 or 면 교차타입은 and를 의미한다

interface Car {
	name: string;
    start(): void;
}

interface Toy {
	name: string;
    color: string;
    price: number;
}

// &(엔퍼센트 기호를 사용)
const toyCar: Toy & Car = {
	name: "타요",
    start(){},
    color: "blue",
    price: 1000,
}

& 엔퍼센트 기호를 사용하고 만들어진 것에 모든 타입을 작성해줘야 한다

클래스

class Car {
	constructor(color) {
    	this.color = color; // 에러 발생 // color 프로펄티가 Car에 없다고 나옴
    }
    start() {
    	console.log("start")
    }
}

const bmw = new Car("red");

타입스크립트에서 클래스 작성할때 멤버 변수는 미리 선언을 해줘야 한다

class Car {

	color: string; // 변수 미리 선언
	constructor(color: string) { // 매개변수 타입도 설정
    	this.color = color; // 에러 발생 // color 프로펄티가 Car에 없다고 나옴
    }
    start() {
    	console.log("start")
    }
}

const bmw = new Car("red");

멤버변수를 미리선언하지 않아도 되는 방법도 있다
접근제한자나 readonly 키워드를 사용하는 방법이 있다

public / readonly

class Car {

	constructor(public color: string) { // 매개변수 타입도 설정
    	this.color = color; // 에러 발생 // color 프로펄티가 Car에 없다고 나옴
    }
    start() {
    	console.log("start")
    }
}

const bmw = new Car("red");
class Car {

	constructor(readonly color: string) { // 매개변수 타입도 설정
    	this.color = color; // 에러 발생 // color 프로펄티가 Car에 없다고 나옴
    }
    start() {
    	console.log("start")
    }
}

const bmw = new Car("red");

public / readonly

es6 클래스는 다른 객체지향 언어들 처럼 접근 제한자를 지원하지 않는다
하지만 타입스크립트에서는 지원한다

접근제한자 (Access modifier) - public, private, protected

public

자식 클래스나 클래스 인스턴스에서 접근이 가능하다
아무것도 표기하지 않고 작성하면 모두 public 이다

class Car {
	name: string = "car"; // 앞에 아무것도 없지만 public이 있는 것과 같다
    color: string;
    constructor(color: string) {
    	this.color = color;
    }
    start() {
    	console.log("start")
    }
}

// Car class를 상속받은 Bmw
class Bmw extends Car {
	constructor(color: string) {
    	super(color); // super가 없으면 에러 발생 // Car에 있는 color, name을 받아 옴
    }
    showName() {
    	console.log(super.name)
    }
}

const z4 = new Bmw("black")

private

class Car {
	private name: string = "car"; 
    color: string;
    constructor(color: string) {
    	this.color = color;
    }
    start() {
    	console.log("start")
    }
}

// Car class를 상속받은 Bmw
class Bmw extends Car {
	constructor(color: string) {
    	super(color); 
    }
    showName() {
    	console.log(super.name) // 에러 발생 // 자식클래스 내부에서 사용할 수 없게 된것
        // name은 Car 클래스 내부에서만 사용가능 하다
    }
}

const z4 = new Bmw("black")
  • # 사용
class Car {
	#name: string = "car";  // #사용으로 private 사용가능
    color: string;
    constructor(color: string) {
    	this.color = color;
    }
    start() {
    	console.log("start")
        console.log(this.#name) // 사용하는 쪽도 #을 써줘야 한다
    }
}

protected

class Car {
	protected name: string = "car"; 
    color: string;
    constructor(color: string) {
    	this.color = color;
    }
    start() {
    	console.log("start")
    }
}

// Car class를 상속받은 Bmw
class Bmw extends Car {
	constructor(color: string) {
    	super(color); 
    }
    showName() {
    	console.log(super.name) // 에러 발생 // 자식클래스 내부에서 사용할 수 없게 된것
        // name은 Car 클래스 내부에서만 사용가능 하다
    }
}

const z4 = new Bmw("black")

protected도 자식 클래스에서 접근이 가능하다,
클래스 인스턴스로는 존재할 수 없다

public은 자식 클래스나 클래스 인스턴스모두 접근 할 수 있다, 아무것도 안적으면 public 이다

protected는 자식 클래스 내부에서만 접근할 수 있다

private는 가장 제한적이며, 해당 클래스 내부에서만 접근할 수 있다
# 변수명으로 적을 수 있다

static property

static을 써주면 정적 멤버변수를 만들 수 있다
이렇게 되면 class.으로 접근이 가능하다

this가 아닌 class 이름으로 접근한다

class Car {
	protected name: string = "car"; 
    color: string;
    static wheels = 4;
    constructor(color: string) {
    	this.color = color;
    }
    start() {
    	console.log("start")
        console.log(Car.wheels) // static을 사용하면 this가 아닌 class 이름을 사용한다
    }
}

consele.log(car.wheels) // static을 사용하면 this가 아닌 class 이름을 사용한다

추상 클래스

추상클래스는 클래스 앞에 abstract 키워드를 사용해서 만들 수 있다

class Car {
	color: string;
    constructor(color: string) {
    	this.color = color;
    }
    start() {
    	console.log("start")
    }
}

const car = new Car("red"); // 에러발생 // new키워드로 객체를 만들 수 없다

// 하기와 같이 상속을 통해서만 사용이 가능하다
class Bmw extends Car {
	constructor(color: string) {
    	super(color)
    }
}

const z4 = new Bmw("black")

추상메소드는 반드시 상속받은 쪽에서 구체적인 구현을 해줘야 한다

class Car {
	color: string;
    constructor(color: string) {
    	this.color = color;
    }
    start() {
    	console.log("start")
    }
    abstract doSomething():void;
}

class Bmw extends Car { // 에러 발생 // 구체적인 구현 필요
	constructor(color: string) {
    	super(color)
    }
}

const z4 = new Bmw("black")

추상화는 프로퍼티나 메서드의 이름만 선언해주고,
구체적인 기능은 상속받는 쪽에서 구현해주는 것을 의미한다

추상 클래스를 상속받아 수많은 객체들이 동일하게 이 메서드를 가지고 있겠지만,
구체적인 기능은 가지각색일 수 있다

class Car {
	color: string;
    constructor(color: string) {
    	this.color = color;
    }
    start() {
    	console.log("start")
    }
    abstract doSomething():void;
}

class Bmw extends Car { // 에러 발생 // 구체적인 구현 필요
	constructor(color: string) {
    	super(color)
    }
    doSomething(){
    	alert(3);
    }
}

const z4 = new Bmw("black")

제네릭 (Generic)

제네릭을 이용하면 클래스나 함수 인터페이스를 다양한 타입으로 재사용 할 수 있다

선언할때는 타입 파라미터만 적어주고 생성는 시점에 사용하는 타입을 결정한다

function getSize(arr: number[]):number {
	return arr.length;
}

const arr1 = [1, 2, 3];
getSize(arr1); // 3

arr1 이 number 타입만 사용하면 상관없는데, 만약 string, boolean 등 값들이 많아지면

function getSize(arr: number[], string[]):number

이렇게 계속 추가해줘야 한다

function getSize<T>(arr):number {
	return arr.length;
}

const arr1 = [1, 2, 3];
getSize(arr1); // 3

const arr2 = ["a", "b", "c"];
getSize(arr2);

const arr3 = [false, true, true];
getSize(arr3);

const arr4 = [{}, {}, { name: "Tim" }];
getSize(arr4);
profile
즐겁게 살자

0개의 댓글