타입스크립트 문법

merci·2023년 7월 3일
0

typescript

목록 보기
1/2

https://www.typescriptlang.org 에서 타입스크립트를 설치하지 않고 문법을 연습할 수 있습니다.

문법

Optional

? 를 넣어서 Optional 프로퍼티로 만듭니다.
Optional은 초기화하지 않고 접근한다면 undefined을 반환합니다.

  • Optional Property
type Player = {    // { } => object
  name: string,
  age?: number
};

const person1: Player = {
  name: "John"
};

const person2: Player = {
  name: "Jane",
  age: 25
};
  • Optional Parameter
function greet(name: string, age?: number) {
  console.log(`Hello, ${name}! ${age ? `You are ${age} years old.` : ""}`);
}

greet("John"); // Hello, John!
greet("Jane", 25); // Hello, Jane! You are 25 years old.

Optional Chaining

&& 연산자로 안전하게 사용할 수 있습니다.

if( person1.age && person1.age < 20) { // undefined 방지
    console.log("Yor are teenager.")
}

또는 ?. 를 이용할 수 있습니다.

const address = person2.address?.city; // undefined 반환

if (address === undefined) {
  console.log("Result is undefined."); // Result is undefined.
}

함수 선언문, 함수 표현식

함수에도 타입을 명시할 수 있습니다.

if( person2.age && person2.age > 20) {
  const answer = playerMaker(person1.name);
  const returnAge = ageReturn(person2.age);
  answer.age = 30; // type: Player
  console.log(`${answer.name} -> ${answer.age}, ${person2.name} -> ${returnAge}`)
}   													// "John -> 30, Jane -> 25" 

function playerMaker(name: string): Player { // 명시
  return {
    name
  }
}

function ageReturn(age: number) {
  return age;
}

위 코드를 보면 타입스크립트에서 함수 선언문은 호이스팅이 가능하지만 함수 표현식은 호이스팅이 안되므로 먼저 선언해야 합니다.

const playerMaker = (name: string): Player => ({name})

const answer = playerMaker("Niko");

readonly

불변으로 만들어서 읽기만 가능하도록 합니다.

type Player = {
  readonly name: string,
  age?: number
};
const person1: Player = {
  name: "John"
};

const playerMaker = (name: string): Player => ({name})
const answer = playerMaker(person1.name);
answer.name = "Kane"; // Cannot assign to 'name' because it is a read-only property.
const numberArr : readonly number[] = [1, 2, 3, 4]
numberArr.push(5); // Property 'push' does not exist on type 'readonly number[]'.

튜플

const person: [string, number, boolean] = ["John", 25, true];

console.log(person[0]); // "John"
console.log(person[1]); // 25



타입 연산자

타입 시스템을 통해 타입을 조작하고 변환하는 기능을 제공합니다
타입스크립트가 사용하지 못하는 unknown 타입( 명시 )을 타입연산자로 정제하여 사용할 수 있습니다.

typeof

타입을 문자열로 반환합니다.

const x = 10;
console.log(typeof x); // "number"

let a: unknown;
if(typeof a === 'number'){
  let b = a + 1
}

keyof

객체 타입의 모든 속성 이름을 유니온 타입으로 반환합니다.

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

type PersonKeys = keyof Person; // "name" | "age"

in

객체가 특정 속성을 가지고 있는지 확인합니다.

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

type HasAge = "age" in Person; // true



never

아래 함수는 값을 반환하지 않습니다.

function throwError(msg: string): never {
    throw new Error(msg)
}

아래의 타입가드에서 걸러지지 않고 else문으로 간다면 never타입을 반환하므로 리턴되지 않습니다.

function validate(value: string | number): string {
  if (typeof value === "string") {
    return value.toUpperCase(); // string
  } else if (typeof value === "number") {
    return value.toFixed(2); // number, toFixed( 3.1415 -> 3.14 반올림 )
  } else {
    const _exhaustiveCheck: never = value; // value 는 never 타입
    throw new Error(`Unexpected value: ${_exhaustiveCheck}`);
  }
}



함수

Call signature

변수에 마우스를 올리면 Call signature를 확인할 수 있습니다.

함수의 타입을 정의할때 매개변수와 반환 타입을 지정하면 해당 타입의 함수는 타입을 지정하지 않아도 됩니다.

type Add = (x: number, y: number) => number;

const add: Add = (a, b) => a + b

overloading

유니언 타입을 이용해서 함수를 오버로딩합니다.

type ConcatFunction = {
  (x: string, y: string): string;
  (x: number, y: number): number;
  (x: string | number, y: string | number): string | number;
};

const concat: ConcatFunction = (x: string | number, y: string | number): string | number => {
  if (typeof x === "string" && typeof y === "string") {
    return x + y;
  } else if (typeof x === "number" && typeof y === "number") {
    return x + y;
  } else {
    throw new Error("Invalid arguments");
  }
};

console.log(concat("Hello, ", "World")); // "Hello, World"
console.log(concat(5, 10)); // 15

라우팅시 오버로딩을 자주 이용합니다.

type Config = {
  	path: string,
  	state: object
}

type Push = {
  	(path: string): void
  	(config: Config): void
}

const push: Push = (config) => {
  if(typeof config === 'string') console.log(config)
  else console.log(config.path) 
}

const test = "/home"
const configTest = {
    path: "/join",
    state: {}
}
push(test) //   "/home"
push(configTest) //   "/join"

매개변수의 갯수가 다르게 오버로딩될 경우는 optional을 이용합니다.

type Add = {
  (a: number, b: number): number,
  (a: number, b: number, c:number): number
}
const add: Add = (a, b, c?: number) => {
  	if(c) return a + b + c
 	return a + b 
}
console.log(add(1,2,4)) // 7

제네릭

오버로딩의 경우가 많아지거나 복잡해질경우 제네릭을 사용해서 한번에 받도록 할 수 있습니다.

type SuperPrint = {
  <T>(arr: T[]): void
}
const superPrint: SuperPrint = (arr) => {
 	arr.forEach(i => console.log(i)) 
}
superPrint([1,2,3,4]) 
superPrint([true, false, "happy"])

제네릭 함수

function superPrint<T>(a: T[]){
  return a[0]
}
const b = superPrint([true, false, false])
console.log(b) // true

제네릭 타입

type Player<T> = {
  name: string,
  extra: T
}
const doe: Player<{food: string}> = {
 	name: "doe",
  	extra: {
     	food: "Hamberger" 
    }
}

배열 선언

type A = Array<number>

let a: A = [1, 2, 3, 4]



클래스

추상클래스

자바스크립트 코드로 컴파일 될때 abstract 나 접근 제한자는 js코드에 보이지 않습니다.
추상클래스는 공통된 특성을 상속클래스에 전달하므로 상속 클래스는 멤버변수를 추가하지 않아도 됩니다.
또한 추상클래스는 인스턴스를 만들 수 없습니다.

abstract class User {
    constructor(
        private firstName: string,
        private lastName: string,
        public nickNama: string
    ){}   // 자바스크립트로 컴파일하면 this.a = a 를 만들어 준다.
    getFullName(){
       // return this.firstName +"   "+ this.lastName  // Amiah   Miller
       return `${this.firstName} ${this.lastName}`  
    }
}
class MyPlayer extends User{
}

const nicol = new MyPlayer("Amiah", "Miller", "22")
console.log(nicol.getFullName())  // Amiah Miller

추상 클래스를 만들게 되면 상속하는 클래스에서 구현해야 합니다.

abstract class User {
	// 생략
    abstract getNickName(): string
}
class MyPlayer extends User{
    getNickName(){
        return this.nickName
    }
}
const nicol = new MyPlayer("Amiah", "Miller", "22")
console.log(nicol.getNickName())  // 22

해시 테이블 구조

type Words = {
    [key: string]: number  // key - value
}

class Dict {
    private words: Words
    constructor(){
        this.words = {}  // 빈 객체로 초기화
    }
    add(word: Word){
        if(this.words[word.term] === undefined)
            this.words[word.term] = 1
    }
    count(term: string){
        return this.words[term]
    }
}

class Word {
    constructor(
        public term: string,
        // public readonly term: string,
        public count: number
    ){}
}

const tomato = new Word("토마토", 1)
const dict = new Dict()  // dict.words -> 빈 객체
dict.add(tomato)
console.log(dict.count("토마토")) // 1

not concrete type

string, number 같은 구체적인 타입(concrete type)이 아닌 개발자가 커스텀한 타입으로 만들 수 있습니다.

type Team = "red" | "blue" | "yellow"

type OnePlayer = {
    nickname: string,
    team: Team
}
const jack: OnePlayer = {
    nickname: "jack",
    team: "blue"
}

인터페이스

위 코드를 인터페이스로 바꿀 수 있습니다.

interface OnePlayer {
    nickname: string,
    team: Team  
}

인터페이스를 통해 객체의 구조를 강제할 수 있습니다.
구조를 강제하므로 상속하는 클래스는 동일한 멤버변수와 메소드를 구현해야 합니다.

interface Person {
  name: string;
  age: number;
  greet(): void;  // abstract
}

interface Human {
  health: number 
}
class Student implements Person, Human {
  constructor(
    public name: string, 
    public age: number,
    public health: number
  ) {}
  
  greet() {
    console.log(`Hello, my name is ${this.name}.`);
  }
}

const student = new Student("Alice", 20, 10);
console.log(student.name);  //  Alice
console.log(student.age);  //  20
student.greet();  //  Hello, my name is Alice.

인터페이스를 구현하는 클래스의 멤버변수는 public이 되어야 합니다.
또한 타입스크립트에서 인터페이스는 추상 클래스와 다르게 자바스크립트 코드로 컴파일 되지 않습니다.

제네릭과 인터페이스를 함께 이용해서 사용할 수 있습니다.

interface MyStorage<T> {
    [key: string]: T
}
class LocalStorage<T> {
    private storage: MyStorage<T> = {
    }
    public set(str: string, value: T){
		this.storage[str] = value
    }
    public clear(){
        this.storage = {}
    }
    public get(str: string) {
        return this.storage[str]
    }
}

const homeStorage = new LocalStorage<number>();

homeStorage.set("서랍", 1203)
console.log(homeStorage.get("서랍"))  // 1203
homeStorage.clear()
console.log(homeStorage.get("서랍"))  // undefined
profile
작은것부터

0개의 댓글