DBILITY

독거 가능성 100% 노후에 라면값이라도 하게 센스를 발휘합시다!😅
Please click on the ad so that I can pay for ramen in my old age!
点击一下广告,让老后吃个泡面钱吧!
老後にラーメン代だけでもするように広告を一回クリックしてください。

typescript 기초 본문

front-end & ui/typescript

typescript 기초

DBILITY 2021. 12. 23. 14:22
반응형

typescript가 존재하는 이유는 javascript의 dynamic typing 때문?

dynamic typing은 할당된 값에 따라 알아서 척척 type casting을 해주는 것으로 생각하면 된다.

이로 인해 런타임에서야 확인 가능한 명확하지 않은 경고와 오류에 빠지게 되었다.

오류~ typescript에서 try catch block으로 처리하려는데 error catch가 되지 않음..error의 type은 뭔가? unknown이라니..일단 any로 하니 잡히기는 한다. 근데 any는 곤란하다..throw를 통해 생성된 것과 구분만 해봤다.

    try {
      ....
      throw new Error('알고 싶지 않아');
      ....
    } catch (error) {
      console.log(error);
      //toastify
      toast.error((error instanceof Error?error.message:String(error)),{theme: "colored"});
    }

typescript는 이름그대로 type+javascript? ms에서 개발했다. 

이게 직접 실행되는게 아니라 javascript로 변환을 해서 실행을 한다. 결국 editor에서 개발할때 필요한 것이 되겠다.

우선 tsconfig.json파일을 만들어 주고, 내용을 채워준다. 

https://www.typescriptlang.org/ko/docs/handbook/tsconfig-json.html

 

Documentation - What is a tsconfig.json

Learn about how a TSConfig works

www.typescriptlang.org

변수의 type을 지정할 수 있다.  다른 type을 할당하면 오류를 뿜어준다.
그림 1은 name이라는 변수를 선언하고, 값을 할당했다. 에디터에서도 빨간 줄 쫘~~악! 읽어보면 된다.

그림 1
그림 2

많이 쓰는 array object는 다음과 같이 선언하니 된다. type지정을 잘해줘야 ide에게 욕을 먹지 않는다..

const data: { title: string, shipdate: string }[] = [
  {title: '사과', shipdate: '20230608'},
  {title: '배', shipdate: '20230608'},
  {title: '감', shipdate: '20230608'}
];

array, object type도 지정 가능하고 심지어 OR로 지정(union type)도 된다. 이 무슨 일인가?
심지어 [ 그림 3 ]처럼 type(literal type)을 선언할 수 도 있다.

그림 3
그림 4

기존 js에서처럼 음식점 주문 중 가장 어렵다는 `아무거나` 할당하고 싶을때는 any type이 있다. 막 쓰면 의미가 없다. 꼭 써야 할 곳이 있겠다 아마도.

나는 몰라요에 해당하는 unknown도 있다. any는 위험하니 unknown이 더 낫겠다. unknown은 연산이 안된다.

type도 export, import가 된다. xxxx.d.ts라고 파일을 만들고 type들만 모아 둘 수 도 있다.

object도 type을 줄 수 있는데, 이때는 interface를 쓴다고 한다.

type alias와 다른 건 equal이 없고, extends가 가능? type은 중복선언이 안되는데 interface는 된다. 그냥 합쳐진다.아이고 머리야... method도 interface 선언해서 구현하면 되는구나...오호..OOP와 비교를 잘해야 한다.

interface를 export 하거나 import할때는 export|import type {interface}라고 해야 한다.

interface TypeItem {
  title: string,
  shipdate: string
}

const data: TypeItem [] = [
  {title: '사과', shipdate: '20230608'},
  {title: '배', shipdate: '20230608'},
  {title: '감', shipdate: '20230608'}
];

/*
type Shape = { color: string}
type Circle = { radius: number } & Shape;
type Square = { width: number } & Shape;
*/
interface Shape {
    color: string
}

interface Shape {
    position?: number
}

interface Circle extends Shape {
    radius: number
}

interface Square extends Shape {
    width: number
}

let circle: Circle = {color: 'red', radius: 100}
let square: Square = {color: 'red', position: 0, width: 100}

interface Calc {
    plus: (x: number, y: number) => number
    minus: (x: number, y: number) => number
}

let myCalc: Calc = {
    plus(a, b) {
        return a + b;
    },
    minus(a, b) {
        return a - b;
    }
}

당연하게도 함수 파라미터,결과값도 type을 선언할 수 있다. type미지정시 any type...이러면 완전 나가린데.

function 함수(파라미터: number): number {
    return 파라미터 * 2;
}

리턴값이 없을때..예상대로 void를 주면 된다. parameter,return type 모두 union type 가능하다.

특별한 경우로 리턴값을 갖고 싶지 않을때 never, 오류처리 함수 같은 경우 영원히 끝나지 않는 함수에 쓴다. 근데 말이 너무 어렵다. 코드 어디에 등장하는 영문 그대로 never의 의미다. 생각과 다르게 나타났다면 코드를 수정해야 한다고 함.

다음은 숫자를 받아 들여 최대값을 리턴하는 함수다.rest parameter를 사용했다.

function fnMaxVal(...params:number[]):number {

    let maxVal = params.reduce((prev:number, curr:number):number => {
        return prev>curr?prev:curr
    });

    return maxVal;
}

parameter가 union type일때 type에 따라 코드를 분기해야 할 수 있다. 이걸 type narrowing이라 한다.

말그대로 narrowing(협소화). 코드에 섬세한 터치가 필요한 거다. typeof, Type이 class일때는 instanceof, object내의 속성 등에는 배타적 속성이 있을때는 in 등으로 비교하면 되겠다.

일일히 하기 싫다면 type assertion을 해주면 된다. 파라미터 as type 형태다. 대신 type이 확실할때만 써야겠다.

마구 쓰다보면 100% 런타임에 오류 발생 할 수 있겠다.

class도 당연히 필드나 메소드에 type을 지정할 수 있다. javascript es6의 class와 다른 점은 필드를 선언해 줘야 한다는 차이? typescript에서는 나름 access modifer를 제공한다..getter setter는 java랑 혼동하지 말아야..java에서 어쨌더라?

property를 construnctor에서 선언하는 방법도 있다? constructor(public _name:string) 이러면 자동으로 생성이 된다. 신기하다.

type Sex = 'male' | 'female' | 'neutral';

class Person {
    //private readonly _name: string;
    private _age: number;
    protected _sex: 'male' | 'female' | 'neutral';
    static got = 'i am your father';

    constructor(public _name?: string, sex?: Sex) {
        this._name = _name ? _name : 'noname';
        this._age = 10;
        this._sex = sex ? sex : 'neutral';
    }

    public sayWelcome(): void {
        console.log(`이랏샤이 ${this._name}`)
    }

    get age(): number {
        return this._age;
    }

    set age(value: number) {
        this._age = value;
    }

    getAge(): number {
        return this._age;
    }

    setAge(age: number): void {
        this._age = age;
    }

    get sex(): Sex {
        return this._sex;
    }

    set sex(sex: Sex) {
        this._sex = sex;
    }

}

class Child extends Person {

    static got = 'i am your child';
    constructor() {
        super();
    }
}

let person: Person = new Person('홍길동');
person.sayWelcome(); // 이랏샤이 홍길동
console.log(person.age); //10
person.age = 100;
console.log(person.age); //100
person.setAge(1000);
console.log(person.getAge()); //1000
console.log(person.sex); //neutral

let child = new Child();
child.sayWelcome();//이랏샤이 noname
console.log(child.age);//10
child.age = 0;
console.log(child.age);//0
console.log(child.sex);//neutral
child.sex = 'male';
console.log(child.sex);//male
console.log(Person.got);
console.log(Child.got);

javascript로 변환 되면 다음과 같이 된다...와우...

var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        if (typeof b !== "function" && b !== null)
            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var Person = /** @class */ (function () {
    function Person(_name, sex) {
        this._name = _name;
        this._name = _name ? _name : 'noname';
        this._age = 10;
        this._sex = sex ? sex : 'neutral';
    }
    Person.prototype.sayWelcome = function () {
        console.log("\uC774\uB78F\uC0E4\uC774 ".concat(this._name));
    };
    Object.defineProperty(Person.prototype, "age", {
        get: function () {
            return this._age;
        },
        set: function (value) {
            this._age = value;
        },
        enumerable: false,
        configurable: true
    });
    Person.prototype.getAge = function () {
        return this._age;
    };
    Person.prototype.setAge = function (age) {
        this._age = age;
    };
    Object.defineProperty(Person.prototype, "sex", {
        get: function () {
            return this._sex;
        },
        set: function (sex) {
            this._sex = sex;
        },
        enumerable: false,
        configurable: true
    });
    Person.got = 'i am your father';
    return Person;
}());
var Child = /** @class */ (function (_super) {
    __extends(Child, _super);
    function Child() {
        return _super.call(this) || this;
    }
    Child.got = 'i am your child';
    return Child;
}(Person));
var person = new Person('홍길동');
person.sayWelcome(); // 이랏샤이 홍길동
console.log(person.age); //10
person.age = 100;
console.log(person.age); //100
person.setAge(1000);
console.log(person.getAge()); //1000
console.log(person.sex); //neutral
var child = new Child();
child.sayWelcome(); //이랏샤이 noname
console.log(child.age); //10
child.age = 0;
console.log(child.age); //0
console.log(child.sex); //neutral
child.sex = 'male';
console.log(child.sex); //male
console.log(Person.got);
console.log(Child.got);

namespace도 있는데 그냥 c# namesapce를 생각하자. import나 내부에서 type 등등 중복이 발생 할 경우에서만 사용하는게 좋겠다.

다음은 기억을 못하니 적어 두자.

나는 intellij에서 New Project -> Language를 JavaScript로 생성했다.

다음에 Project를 선택하고 New (Alt+INSERT) 에서 tsconfig.json 선택 파일생성.

다시 New..TypeScript File 선택 파일생성. 생성된 파일(.ts)를 tsconfig.json의 files에 입력

그림1

CLI에서 tscscript를 실행(tsc typesript명.ts)하고 나면 typescript명.js가 생성된다.

intellij에선 Languages * Frameworks > TypeScript > TypeScript language servie > Recompile chagnes를 체크하면 자동.

js를 선택하고 실행(SHIFT+F10) , 출력될게 있다면 출력이 된다.

react에 typescript를 써보려고 하니 알아야 할 게 많다..

tag에 onClick event handler 하나 붙이려고 해도 event에 type을 지정해야 하는 것 인가?

span tag에 붙이려니 다음과 같다. 어렵다....

/* eslint-disable */
import React, {JSX, useCallback, useState} from 'react';
import './App.css';

interface TypeItem {
  title: string,
  shipdate: string,
  amount:number
}

const data: TypeItem [] = [
  {title: '사과', shipdate: '20230608',amount:0},
  {title: '배', shipdate: '20230608',amount:0},
  {title: '감', shipdate: '20230608',amount:0}
];

function App(): JSX.Element {
  const [items, setItems] = useState<TypeItem[]>(data);

  const handlerOrder = (e:React.MouseEvent<HTMLSpanElement>):void=>{
    console.log(e.target);
  };

  return (
      <div className="App">
        {
          items.map((item, index): JSX.Element => {
            return (
                <div className={'list'} key={`${item.shipdate}_${index}`}>
                  <h4>{item.title} {item.amount} <span onClick={handlerOrder}>order</span></h4>
                  <p>{item.shipdate}</p>
                </div>
            )
          })
        }

      </div>
  );
}

export default App;

key로 쓸게 필요해서 span tag에 idx를 추가했더니...오류가 난다.. Property 'idx' does not exist on type

돌아 버리겠다..방법이야 있다지만(react의 HTMLAttributes를 재정의) 너무 복잡하다.

https://developer-talk.tistory.com/197

 

[TypeScript]타입스크립트 Property does not exists on type

React 컴포넌트를 TypeScript로 개발할 때, 사용자 정의 HTML 프로퍼티를 사용하는 경우 주로 아래 에러가 발생합니다. 에러 내용 Type '{ type: string;}' is not assignable to type 'DetailedHTMLProps'. Property 'size' does

developer-talk.tistory.com

그냥 dataset property로 해결 tag에 data-idx  handler에선 e.currentTarget.dataset.idx으로 읽어진다.

e.currentTarget.dataset은 DOMStringMap이다. map object.

 

반응형
Comments