타입스크립트_기본타입, interface

mangorovski·2022년 11월 15일
0

Typescript

function showTimes(arr) {
    arr.forEach(element => {
        console.log(element)
    });
}

showTimes([1,2,3]) //1, 2, 3
showTimes(1,2,3) //error 발생
  • Javascript(동적언어):
    실행되는 시점 (런타임)에 타입이 결정되고 오류가 있을 시 그때 처리가 가능하다.
function showTimes(arr:number[]) {
    arr.forEach(element => {
        console.log(element)
    });
}

showTimes([1,2,3]) //1, 2, 3


function showTimes(arr:string[]) {
    arr.forEach(element => {
        console.log(element)
    });
}

showTimes([1,2,3]) //error
  • Java, TypeScript(정적언어)
    컴파일시에 타입이 결정된다.
    코드 작성때 시간이 길어지지만, 생각하고 코드를 짠다면 안정적인 로직 작성이 가능하다.

정리하자면, 타입스크립트를 쓰는 이유?
javascript에 타입이 추가 된 것이다. 그로인해 코드가 올바르게 작동하는지 확인할 수 있다.

[javascript]
function showTime(arr){
    arr.forEach((item) => {
        console.log(item)
    })
}
showTime([1, 2, 3])
showTime(1, 2, 3)

///1
///2
///3
/// error...

//런타임에서 타입이 결정 됨

[첫번째 예제 확인]

function add(num1:number, num2:number){
    console.log(num1 + num2)
}

//add() 
//add(1)
add(1,2)
//add('hello', 'world')

any타입이였던 인수가 number로 고정이 됐다.
인수의 개수가 맞지 않은 부분과 string의 함수 호출부분이 에러가 표시가 됐다.

함수를 만들 때 의도했던 방식 외에 다른 방법은 모두 에러라고 나온다.
몇개의 인수를 어떤 타입으로 전달해야하는지 일일이 코드를 뒤져볼 필요가 없다.

[두번째 예제 확인]


any: 아무 타입이나 가능하다. 도저히 어떤 타입인지 모를때 사용한다. 하지만 가급적이면 사용을 지양한다.


Expected 1 arguments, but got 3
한개의 인수만 필요한데 3개를 받았다는 에러 메세지이다.

function showTime(arr:number[]){
    // arr: number의 배열을 받음
    arr.forEach((item) => {
        console.log(item)
    })
}
showTime([1, 2, 3])

타입스크립트 기본 타입

원시타입

let car:string = 'bmw'

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', 'tue', 'wed']
let week2:Array<string> = ['mon', 'tue', 'wed']

week1.push(3)//error

let u:undefined = undefined
let n:null = null
  • null과 undefined
    모든 타입의 하위 타입으로 number 같은 타입에 할당할 수 있다.
    strickNullChecks를 사용하게 되면 null과 undefined는 오직 any타입과 각자 자신타입에만 할당 가능하다.

참조타입

  • object, array, tupple
object

타입을 지정해주면 지정된 값들만 넣을 수 있게 만들어야 한다.
타입이 길어질경우 가독성이 많이 떨어지기에 보통 타입을 따로 지정해서 사용한다.

  • 각 타입 지정 방법: Type Alias & Interface, index signature
    • type alias: type을 따로 만들어서 사용한다.
    • index signature: [key: string] key값에 어떤 타입이 명세될줄 모르나 전부 string으로 타입을 지정하는 방식이다.
    • union type: string | number 처럼 여러 타입을 같이 선언한다
[기본형]
let obj: {
	name: string;
    age: number;
} = {
	name: 'dabin',
    age: 22
}
[type alias]
type myType = {
	name: string;
    age: number;
}
let obj: myTpye = {
	name: 'dabin',
    age: 22
}
[Type Alias + Index Signature + Union Type]
type myType = {
	[key: string]: string | number
}
let obj: myTpye = {
	name: 'dabin',
    age: 22
}
Array

javascript처럼 자유롭지 못하다.

[기본형]
let a:number[] = [1, 3, 5]
let b:Array<number> = [4, 6, 7]
let week1:string[] = ['mon', 'tue', 'wed' ]
let week2:Array<string> = ['mon', 'tue', 'wed' ]

week1.push('4')

[배열 다중 타입]

let arr: (string|number)[] = [1, '1']
튜플(Tuple)

배열과 비슷하다. 인덱스별로 타입이 다를 때 사용한다.

//배열의 첫번째 요소에는 string 두번째 요소에는 number을 입력할 수 있음]
let ab:[string, number];
ab = ['z', 1]
ab = [1, 'z'] //error

// 문자 => 숫자 toLowerCase
b[0].toLocaleLowerCase()
b[1].toLocaleLowerCase() //number에는 toLocaleLowerCase가 없음


// void, never
void, never
function sayHello():void{
    console.log('hello')
}
  • void는 함수에서 아무것도 반환하지 않을 때 주로 사용한다.
function showError():never{
    throw new Error()
}

function infLoop():never{
   while (true){
    //do something...
   }
}
  • never는 영원히 끝나지 않는 함수나, 항상 에러를 반환하는 함수에서 사용할 수 있다.
enum

열거형으로서 비슷한 값들끼리 묶어준다.
특정값만 입력하게 강조하고 싶을 때 또한 그 값들이 공통점이 있을 때 사용한다.

enum Os{
    Window,
    Ios,
    Android
}

각각 수동으로 값을 할당하지 않으면 자동으로 0부터 1씩 증가되며 값이 할당된다.

enum Os{
    Window,
    Ios = 3,
    Android
}

값을 할당하게 되면 해당 값부터 차례대로 값이 출력되는걸 알 수 있다.
window는 건너뛰고 값을주면 window는 0이된다.

console.log(Os[3]) // [LOG]: "Ios"
console.log(Os['Ios']) // [LOG]: 10

컴파일된 결과를 보면 OS라는 객체가 생성되고 양방향으로 내편되어 있다.
enum에는 숫자가 아닌 물자도 입력이 가능한데, 이럴때는 양방향이 아닌 단방향 맵핑만된다.

enum Os{
    Window = 'win',
    Ios = 'ios',
    Android = 'and'
}

// 숫자가 아닌 문자열도 입력할 수 있다. 이럴 경우 단방향 맵핑만 된다. 

 let myOs : Os;
 //myOs에는 Os에 있는 window, ios, Android만 사용할 수 있게 된다. 

 myOs = Os.Window //특정값만 입력할 수 있게 할 수 있다. 

인터페이스(interface)

let user:object;

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

console.log(user.name)
//콘솔에 있는 name부분이 빨간줄이 그어진다. 

object에는 특정 속성값에 대한 정보가 없기때문에 에러가 발생한다.

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

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

user2.age = 10 

console.log(user2.age)

interface를 통해서 객체의 property를 정의해서 표현해준다.

[property 추가]
interface User{
    name: string,
    age: number,
    gender? : string,
}

있어도되고 없어도 되는 속성을 추가하고 싶을 때는 optional chaining 사용한다.
(* optional chaining: 프로퍼티가 없는 중첩 객체를 에러 없이 안전하게 접근할 수 있다. )키 값뒤에 ? 를 넣어준다.

interface User{
    name:string,
    age:number,
    gender?: string // 입력을 해도 되고 안해도 되는 속성은 optional을 사용한다.
}

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

user.age = 10
user.gender = "male" //error

console.log(user.name) 

만약 gender라는 property가 있을 때는 무조건 string이여야 한다.

[readOnly]

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

interface User{
    gender? : string,
    readonly birthYear: number
}

let user2: User={
    age: 30,
    birthYear: 2000
}

user2.birthYear = 1999
console.log(user2.birthYear)


user2.birthYear = 1999를 입력하면 에러가 뜨게된다.
읽기 전용 속성이라 수정할 수 없다.

[문자열 index 속성]
interface User{
    gender? : string,
    age: number,
    readonly birthYear: number
    1? : string;
    2? : string;
    3? : string;
    4? : string;
}

let user2: User={
    age: 30,
    birthYear: 2000,
    1: 'A'
}

학년별로 interface를 정의해줄 수 있다.
하지만, 1학년만 쓰고 싶을 때는 optional chaining 쓸 수 바께 없다.

이럴 경우에 문자열 index 속성을 사용하면 된다.

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

interface User{
    gender? : string,
    age: number,
    readonly birthYear: number
    //[grade: number] : string
    [grade: number] : Score
}

let user2: User={
    age: 30,
    birthYear: 2000,
    1: 's',  //에러발생 
    2: 'B'
}


// 학년별로 interface를 정의해줄 수 있다. 

[grade: number] : string 학년은 숫자로 받음 : 학점은 string
number를 key로 하고 string value로 받는 property를 여러개 만들 수 있다.

만약 학점을 String으로 받기에는 범위가 너무 넓은데 이럴 때 사용할 수 있는게
문자 리터럴이다.

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

이렇게 추가하게 되면 Score의 입력값만을 사용할 수 있다.

[interface로 함수 정의]
interface Add {
    // (num1: number, num2: number): void
    (num1: number, num2: number): number
}

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


interface IsAdult {
    (age:number): boolean
}

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

console.log(a(7)) //false
console.log(a(11)) //true 
[interface로 클래스 정의]
  • [implements]
interface Car{
    color: string
    wheels: number
    start(): void
}

class Bmw implements Car {
    color = "red"
    wheels = 4
}
  • error가 발생한다. 속성값을 모두 입력해야 하기때문에 start()의 함수도 같이 정의를 해줘야 한다.
interface Car{
    color: string
    wheels: number
    start(): void
}

class Bmw implements Car {
    color = "red"
    wheels = 4
    start(){
        console.log('gogogo')
    }
}
  • [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('gogogo')
    }
}

const b = new Bmw('blue')
console.log(b)
//[LOG]: Bmw: {
  "wheels": 4,
  "color": "blue"
} 
  • [extends]
    인터페이스는 확장이 가능하다. 그럴 때 extends 키워드를 사용한다.
interface Car{
    color: string
    wheels: number
    start(): void
}

interface Benz extends Car{
    door:number
    stop(): void
}

const benz : Benz = {
    door: 5,
    stop(){
        console.log('benz!')
    }
}
console.log(benz.stop())
//에러가 발생된다.

왜 에러가 발생될까?
interface확장 전 Car의 속성들도 모두 입력을 해야한다.

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

interface Benz extends Car{
    door:number
    stop(): void
}

const benz : Benz = {
    door: 5,
    stop(){
        console.log('benz!')
    },
    color:"blank",
    wheels: 4,
    start(){
        console.log('gogo')
    }
}
console.log(benz.stop)

참고로 확장은 여러개를 할 수 있다.
동시 확장이 가능하다.

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

interface Toy {
    name: string
}

interface ToyCar extends Car, Toy{
    price: number
}
profile
비니로그 쳌킨

0개의 댓글