Typescript

이종원·2021년 2월 17일
0

1장. 초기 셋팅 설정

타입스크립트를 npm으로 설치

$ npm install -g typescript

index.html 과 app.ts 파일을 만들기

타입스크립트는 자바스크립트 기반의 언어임으로 자바스크립트 언어는 타입스크립트에서도 유효함

app.ts에 함수 작성

function func(str: string){ // 들어올 파라미터에 타입명시하기
	console.log(str)
}

func('hello world') // 함수 실행

app.ts 컴파일

$ tsc app.ts // app.js 파일이 생성됨

컴파일된 app.js파일은 index.js에 연결

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="app.js" defer></script> 
    //스크립트 태그로 연결로 브라우저 콘솔에 함수가 찍히는걸 볼 수 있다
  </head>
  <body></body>
</html>

Duplicate function implementation 작성한 함수명 밑줄에 에러가 뜨는걸 볼수있다

$ tsc --init // tsconfig.json 파일이 생성되고 에러가 없어짐

매번 app.ts를 작성할때 마다 컴파일 해주기 귀찮기에

$ tsc -w // 변경할때마다 자동으로 컴파일 해준다

2장 Type inference 타입 추론

타입스크립트는 타입표기가 없는 경우 코드를 읽고 분석후 타입을 유추함

숫자 타입의 변수를 생성함

let count = 0 

count에 문자열로 재할당 해보고 숫자로도 재할당 해본다

let count = 0
		count = 'string' //에러 발생 Type 'string' is not assignable to type 'number'
let count = 0
		count = 5 // Found error 0

이처럼 변수를 숫자로 선언했으면 재할당도 숫자로 해야함 즉 타입에 맞게 재할당만 할수있음

다양한 타입을 가진 객체를 하나 만들다

let user = {
    name: '김덕배',
    age: 25 ,
    code: () =>{
        console.log('hello')
    }
}

user.name = 10 // 타입 에러 발생
user.age = '늙음' //타입 에러 발생

이처럼 객체 내부에 있는 키와 밸류 또한 타입이 맞춰서 재할당이 가능함

3장 타입명시

변수를 선언할 때 변수 값의 타입을 명시함으로 변수 값의 데이터 타입을 지정

타입 명시 예제

let userName:string = 'bobokim' // 변수 선언시 변수명에 : 찍고 해당 타입을 작성한다
let age:number = 20
let trueOrFalse:boolean = false

function result(age:number):void{ 
// 파라미터 안에 타입을 적고 그 소괄호 옆에 :를 찍고 함수가 반환하는 결과값 적은 
// void란 함수가 반환하는 값이 없는 경우 void 라고 적는다
// 하지만 반환하는 값이 있는 경우 그 결과값이 문자열이면 :string 숫자면 :number 이렇게 적는다
}

4장 인터페이스

함수 작성

function func(result:number):{ //객체를 리턴하며 이렇게 디테일하게 타입을 지정가능함
	result:number
	answer:string
	ox:boolean
}{
	return {
		result:100,
		ox: true
		answer:'답변'
 }
}

하지만 이처럼 작성시 함수 가독성면에서 안 좋기 때문에

저 정해 놓은 타입을 변수 처럼 사용할 수 있게 인터페이스를 사용한다

interface test {
	result:number
	answer:string
	ox:boolean
}

function func2(result:number):test {
	return {
		result:100
		answer:'답변'
		ox:true
	} 
}

이처럼 같은 기능을 하지만 함수 가독성 면에서 더 보기 편한걸 알수있다 또한 저 인터페이스를 다른 함수에도 적용해 재사용성 또한 좋은걸 알 수 있다

만약에 리턴값으로 객체 내부에 answer이 빠지면 어떨까

interface test {
	result:number
	answer:string
	ox:boolean
}

function func2(result:number):test {
	return {
		result:100
		ox:true
	} 
} // 에러 발생 Property 'answer' is missing in type

인터페이스에 나와있는 값중에서 하나라도 빠지면 안되는걸 알수있다

그러면 이걸 대처 할 수 있는 방법이 있을까 선택적 프로퍼티(' ? ')를 사용한다

interface test {
	result:number
	?answer:string // 선택적 프로퍼티 물음표를 추가함
	ox:boolean
}

function func2(result:number):test {
	return {
		result:100
		ox:true
	} 
} // Found error 0

정상적으로 작동한다

readonly : 인터페이스에 readonly 작성했다면 새로운 함수에서 밸류 값을 바꾸는게 불가능함

4장 열거형 Enum과 리터럴 타입

Enum 은 연관된 아이템들을 묶어서 표현하는 수단

enum 작성하기

enum Genders{
	male = 'male' // 0번쨰
	female = 'female' //그냥 female만 쓰면 해당 숫자만 들어감 1번째
}

적용시키기

enum Genders{
	male = 'male' // 0번쨰
	female = 'female' //그냥 female만 쓰면 해당 숫자만 들어감 1번째
}

interface Student{
    studentId: number 
    studentName: string
    age: number
    gender: Genders // enum을 적용 시키기
    subject :string 
    courseCompleted: boolean 
}

function getStudentDetail(studentId:number):Student
{
    return {
        studentId: 123, 
        studentName: 'kimbobo',
        age: 12,
        gender: Genders.male, // 적용
        subject :'ts', 
        courseCompleted: false
    }
}

console.log(getStudentDetail(studentId))
{
// age: 12 
//courseCompleted: false
// gender: "male" //정확하게 지정된 스트링 male이 적용된걸 알수있다
// studentId: 123
//studentName: "kimbobo"
//subject: "ts"
}

이런 방법을 쓰면 좀 작성할 코드가 많아서 귀찮다 그러면 이번에는 리터럴 타입 방법을 써보자

interface Student{
    studentId: number 
    studentName: string
    age: number
    gender: 'male' | 'female' // 인터페이스에서 들어올 값을 정해준다 
    subject :string 
    courseCompleted: boolean 
}

function getStudentDetail(studentId:number):Student
{
    return {
        studentId: 123, 
        studentName: 'kimbobo',
        age: 12,
        gender: 'male', // 그러고 적용을 해주면 똑같은 값이 출력되는걸 알수있다
        subject :'ts', 
        courseCompleted: false
    }
}

확실히 리터럴 타입이 코드가 간결해서 이걸 많이 쓸거 같지만 혹시 모른다 enum이 중요한 부분에서 사용될 수 있기 때문에 알아두는것이 좋은거 같다

4장 유니언 타입

변수를 선언하고 any라는 타입을 써본다

let test:any = 0
		test = 'hihi' // found error 0
		test = 5 // found error 0
		test = true // found error 0

any를 사용하면 재할당시 모든 타입을 수용 하는것을 알 수 있다

하지만 any를 많이 사용하게 되면 타입스크립트의 취지랑 안맞기 때문에 가능한 사용을 자제 하는것이 좋다

그러면 이번에는 유니언 타입으로 써본다

let test: number | string = 0
		test = 'bye' // found error 0
		test = 7 // found error 0
		test = false // 에러 발생

이처럼 유니언 타입은 설정한 두가지의 타입만 허락하는 것을 알수 있다

하지만 저 타입이 여러곳에서 사용된다면 type aliases 를 사용해 변수처럼 재사용한다

type StrOrNum = number | string

let test: StrOrNum = 0 // found error 0
let test2: StrOrNum = 'good' // found error 0

만약 그냥 유니언 타입으로 여러 변수에 지정해 줬다면 코드가 난잡해지고 가독성이 떨어질 것이지만 이를 통해 좀더 간결한 코드를 생성 할수있다

5장 선택적 매개변수와 기본 매개변수

함수를 작성한다

function func(word : string, name:string):void{ //void: 반환하는 값이 없는경우
    console.log(`${name} ${word}`)
}

func('hello', 'bobo') // hello bobo

만약에 두개의 매개변수 받는 함수에서 하나만 적는경우 에러를 반환 할 것이다 이럴때는 선택적 매개변수 키워드인 ' ? '를 사용한다

function func(word : string, ?name:string):void{ //void: 반환하는 값이 없는경우
    console.log(`${name} ${word}`)
}

func('hello') // hello undifined

undifined를 없애고 기본값을 부여해보자

function func(word = 'hi', name='user'):void{
    console.log(`${word} ${name}`)
}

func() //hi user
func('goodbye') //goodbye user
func('hello', 'bobo') //hello bobo

undifined가 출력 안 되는걸 알 수 있다

5장 인터페이스 상속 및 타입엘리어스

interface Person {
    name:string;
    age?:number
}

const person: Person ={
    name: '사람',
    age: 10,
}

Person 인터페이스를 재사용하고 싶다면

interface Person {
    name:string;
    age?:number
}

interface Developer extends Person {
    skills: string[]
}

const developer: Developer = {
    name: '김개발',
    skills: ['java', 'react', 'node']
}

extends 키워드를 넣어주고 추가적으로 원하는 타입을 지정해주고 사용하면 된다

이번에는 위와 같은 코드이지만 인터페이스를 작성을 안하고 코드를 작성해본다

type Person {
    name:string;
    age?:number
}

type Developer = Person & {
    skills: string[]
}

const person: Person ={
    name: '사람',
    age: 10,
}
 
const developer: Developer = {
    name: '김개발',
    skills: ['java', 'react', 'node']
}

이는 타입 엘리어스를 사용한것이다 좀 더 간단하지만 둘다 똑같이 작동하는걸 알수있다

하지만 때로는 타입 엘리어스를 못쓰고 인터페이스를 써야하는 경우가 있다

이는 라이브러리를 위해 타입을 지정하는 경우 인터페이스를 사용하는걸 권장한다

6장 Generics

객체를 합치는 함수를 작성한다

function merge(a:object, b:object) {
    return {
        ...a,
        ...b
    }
}

const merged = merge({foo:1},{bar:2, foobar:3})

console.log(merged)
console.log(merged.foo) // 에러

선언한 merged 마우스커서를 대면 빈객체라고 나온다

이때 우리는 Generics를 사용한다

예제 1

function merge<T1, T2>(a:T1, b:T2) {
    return {
        ...a,
        ...b
    }
}

const merged = merge({foo:1},{bar:2, foobar:3})

console.log(merged)
console.log(merged.foo) //작동

예제 2

function wrap<T>(param:T){
    return {
        param
    }
}
const wrapped = wrap('aaa')

console.log(wrapped) //작동

예제 3

interface Items<T> {
    list: T[]
}

const items: Items<number> = {
    list: [1,2,3]
}

console.log(items)

인터페이스로 작성된 코드를 타입엘리어스로 작성해본다

예제 3-1

type Items<T, V> = {
    list: T[]
    value: V
}

const items: Items<number, string> = {
    list: [1,2,3],
    value: 'aaa'
}

console.log(items)

interface을 type 이라고 변경하고 " = " 만 붙여주면 동일하게 작동하는 코드이다

0개의 댓글