본문 바로가기
Frontend/Javascript・Typescript

[Typescript] Typescript Essentials2

by 디스코비스킷 2023. 11. 1.
반응형

04. type annotation, type inference

type annotation
개발자가 타입을 타입스크립트에게 직접 말해주는것
const rate: number = 5

type inference
타입스크립트가 알아서 타입을 추론하는것
const rate = 5

타입을 추론하지 못해서 타입 annotation을 꼭 해줘야하는 경우

  • any타입을 리턴하는경우
    const json = '{"x": 4, "y": 7}'
    const coordinates = JSON.parse(json)
    console.log(coordinates)
    coordinates에 hover해보면 const coordinates: any라고 뜨는것을 볼 수 있다. JSON.parse는 json을 파싱해준다. 인풋으로 들어가는 json을 확인하면 대충 어떤 타입이 리턴될지 개발자는 예상할 수 있지만, 타입스크립트는 여기까지 지원하지 않는다. 리턴 타입이 일정하지 않으므로 any를 리턴한다고 추론해버린다. 그러므로 이경우에 타입 annotation을 해주어야한다.
  • 변수 선언을 먼저하고 나중에 초기화 하는 경우
    변수 선언과 동시에 초기화하면 타입을 추론하지만, 선언을 먼저하고 나중에 값을 초기화할때에는 추론하지 못한다.
    let greeting
    greeting = 'hello' // let greeting: any
  • 변수에 대입될 값이 일정치 못한 경우
    여러타입이 지정되어야 할 때에는 |(or statement)로 여러 타입을 annotation해준다.
    let num = [-7, -2, 10]
    let numAboveZero: boolean | number = false
    

for(let i = 0; i <num.length; i++) {
if(num[i] > 0) {
numAboveZero = num[i]
}
}


## 05. 타입스크립트 개발 환경 구성

설치할것 : code editor(VS), nodejs, npm(nodejs설치시 같이 설치됨)
폴더생성

타입스크립트설치 `npm install -g typescript` 
`tsc main.ts`를 하면 js로 컴파일되면서 main.js가 생성된다. 
그 main.js를 html파일에서 열어주면 됨. 

처음은 ES3 문법으로 컴파일되는데 ES6로 버전으로 컴파일할 수 있게 따로 설정가능하다.

`tsc main.ts -w`로 watch설정을 하면 수정하고 저장될때마다 자동 컴파일된다. 


## 06. tsconfig.json 설정하기
tsconfig.json 만들고
```json
{
    "compilerOptions": {
        "rootDir": "./src", // 소스 파일 안에서 root폴더 명시
        "outDir": "./build/js", // ts 컴파일 후에 어느 경로로 들어가는지 명시
        "target": "ES2015", // 타입스크립트를 ES2015버전의 자바스크립트로 변환
        "noEmitOnError": false, // 파일에 에러가 있을 때에는 컴파일 하지 않는 옵션 
        "module": "ESNext", // 컴파일을 마친 후 자바스크립트가 사용한은 모듈 시스템
        "moduleResolution": "Node", 
        "esModuleInterop": true, // ESM(ES Module), CommonJS 호환해서 사용 가능
        "lib": ["ESNext", "DOM"], // 컴파일 과정에서 사용하는 라이브러리 지정
        "strict": true, // 타입스크립트 파일에 타입을 엄격하게 사용한다고 명시
    },
    "include": [ // 소스파일의 어디에서 타입스크립트 파일을 찾을 수 있는지 명시
        "./src/**/*.ts", // src 폴더안에 모든 하위 경로, 모든 ts 파일
    ],
    "exclude": [ // 컴파일시 제외할 목록
        "node_modules"
    ]
}
  • rootDir 설정
  • outDir 설정
  • src폴더 안의 파일만 컴파일 설정하기 : include에서 src안의 모든 ts파일 설정
  • noEmitOnError: false 에러가 있더라고 파일이 emit된다.

07. 타입들 사용해보기

// boolean
let boolean: boolean
let falseBoolean: boolean = false

// number
let number: number
let integer: number
let float:number = 1.234

// string
let string: string
let firstName: string ="Doe"

// Array
// 한가지 타입만 가지는 배열
let names1: string[] = ["John", "Kim"]
let names2: Array<string> = ["John", "Kim"]

// 여러 타입을 가지는 배열(union)
let array1: (string | number)[] = ['John', 1, 2]
let array2: Array<string | number> = ['John', 1, 2]

// 여러타입을 단언할수없다면 any
let someArray = ['John', 1, [], {}, false];

// interface, type

// 읽기전용 배열(readonly, ReadonlyArray)
let stringArray: readonly string[] = ['A', 'B', 'C']
let numberArray: ReadonlyArray<number> = [1, 2, 3]

stringArray.push('C')  // error
numberArray[0] = 3 // error

// Tuple 배열과 비슷하지만 해당자리의 타입과 고정된 길이를 지켜야함
let tuple1: [string, number]
tuple1 = ['a', 1]
tuple1 = ['a', 1, 2] // error
tuple1 = [2, 'a']; // error

let users: [number, string][]
users = [[1, 'John'], [2, 'Doe']]

let tuple2: [string, number]
tuple2 = ['a', 1]
tuple2.push(2) // 허용된 타입일경우 push로 값을 넣는것 가능
console.log(tuple2)


// any
let any: any = 'abc'
any = 1
any = []

// unknown
let unknown: unknown = false
let string1: string = unknown // error 다른 값에 할당불가
let string2: string = unknown as string // 타입단언하면 가능

// object
let obj: object = {}
let arr: object = []
let nul: object = null // error. typeof null은 'object'로나오긴하지만
let date: object = new Date()

const obj1: {id: number, title: string} = {
    id: 1,
    title: 'title1',
    description: 'description' // error
}

// Union
let union: (string | number) 
union = 'hi'
union = 1
union = [] // error

// Function
let func1: (arg1: number, arg2: number) => number
func1 = function(x, y) {
    return x * y
}

let func2: () => void
func2 = function() {
    console.log('Hellow world')
}

// Null, undefined
// strict이 false일때 전부 가능함
let number1: number = undefined 
let string4: string = null
let object: {a: 10, b: false} = undefined
let array: any[] = null
let null1: null = undefined
let void1: void = null

let void2: void = undefined // 가능

// void
function greeting(): void {
    console.log("hi")
}

// never
function keepProcessing(): never {
    while(true) {
        console.log("hi");
    }
}

const never: [] = []
never.push(1) // error

const never2: number[] = []
never2.push(1) // 가능_텍스트_

08. 타입 단언(type assertion)과 타입 Guard

타입 단언(type assertion)이란?

Typescript에선 시스템이 추론 및 분석한 타입 내용을 우리가 원하는대로 얼마든지 바꿀 수 있다. 이때 타입단언이라 불리는 매커니즘이 사용된다.
type assertion을 사용하면 값의 type을 설정하고 컴파일러에 이를 유추하지 않도록 지시할 수 있다. 이것은 프로그래머로서 typescript가 자체적으로 추론할 수 있는것보다 변수 유형에 대해 더 잘 이해하고 있을때입니다.

var foo = {};
foo.bar = 123; // error
foo.bas = 'hello'; // error

컴파일러는 foo 타입이 속성이 없는 {}라고 가정하기 때문에 컴파일러 오류가 발생한다.
아래와 같이 type assertion을 사용하면 이러한 상황을 피할 수 있다.

interface Foo {
    bar: string;
      bas: string;  
}
var foo = {} as Foo;
foo.bar = 123;
foo.bas = 'hello';

타입단언 예제

// 1. 타입 단언
const bodyElement = document.querySelector('body') as HTMLBodyElement;
bodyElement.innerText = "Hello";

// 2. ! not null 타입 단언
const bodyElement1 = document.querySelector("body");
bodyElement1!.innerText = "Hello"; // undefined나 null 이 아니다!


// 3. type guard
const bodyElement2 = document.querySelector("body"); 
if(bodyElement2) { 
    bodyElement2.innerText = "Hello";
}

잘못된 타입단언

function func(arg: string | null) {
  return (arg as string).toLowerCase()
}

func('hello');
func(null); // error

arg를 string으로 단언하는데 null이 들어가면 컴파일에러가 난다.
type guard를 넣어 수정하면된다.

function func(arg: string | null) {
  if(arg) {
    return (arg as string).toLowerCase()
  }
}

func('hello')
func(null)

09. Type Alias vs Interface

Type Alias와 Interface는 타입의 이름을 지정하는 방법으로 매우 유사하고 대부분의 경우 자유롭게 선택할 수 있다.

차이점

Interface의 확장: extends를 이용

interface Animal {
    name: string;
}

interface Bear extends Animal {
    honey: boolean;
}

const bear1: Bear = {
    name: 'honey bear',
    honey: true
}

Type의 확장: Intersection을 이용

type Animal = {
  name: string;
}

type Bear = Animal & {
  honey: boolean;
}

const bear1: Bear = {
  name: "honey bear",
  honey: true,
};

Interface 선언 병합(Declaration Merging)

interface는 되지만 type alias는 선언병합이 안된다.

interface Animal {
  name: string;
}

interface Animal {
  honey: boolean;
}

const bear1 = {
  name: 'honey bear',
  honey: true
}

공통점

Implements 사용가능

Type과 interface 모두 클래스에 implements를 사용할 수 있다.

interface IArticle {
  category: string;
  content: string;
}

class Article implements IArticle {
  public category = "";
  public content = "";
}


type IArticle2 = {
  category: string;
  content: string;
}

class Article2 implements IArticle {
  public category = "";
  public content = "";
}

Union

Union 유형을 사용하면 개발자가 타입A 또는 타입B가 될 수있는 새 Type를 만들수있다. | 연산자를 사용하여 Type과 Interface를 모두 사용하여 새로운 Union 유형을 생성한다. 그러나 선언은 항상 type이어야 한다.

// interface
interface Animal {
  name: string;
}

interface Bear extends Animal {
  honey: boolean;
}

type NewType = Animal | Bear;

const bear1: NewType = {
  name: "honey bear",
  honey: true,
};

// type
type Animal2 = {
  name: string;
}

type Bear2 = Animal & {
  honey: boolean;
}

type NewType2 = Animal | Bear;

const bear2: NewType2 = {
  name: "honey bear",
  honey: true,
};
반응형

최근댓글

최근글

© Copyright 2024 ttutta