자바스크립트와 다른점이 뭘까?
거의 모든 게 JS와 호환되기에 사실상 슈퍼셋임!
npm init -y
로 패package.json 초기화npm i -D typescript
로 타입스크립트 설치간단하구먼!
들어오는 매개변수들의 타입을 유추해서 타입까지 붙여주려한다!
좋은걸?
하지만 우리는 JS처럼 타입대충대충모드를 원하는 게 아니라 엄격모드를 원한다.
따라서 기본 설정을 해주어야한다.
tsconfig.json
파일 생성후
{
"compilerOptions": {
"strict": true
},
"include": [
"src/**/*.ts"
]
}
이렇게 엄격모드와 적용할 위치를 정해주면
이렇게 에러가 나온다!
변수: 타입1 | 타입2 | 타입3...
이렇게 사용한다.
문자 타입을 설정해두어서 숫자와 불리언은 들어가지 못한다!
자바크스크립트로 변환이 필요하다.
//package.json...
"scripts": {
"tsc":"tsc src/main.ts"
},
요래 써놓고 npm run tsc
쓰면 됨!
템플릿 리터럴이 concat
으로 되어있네....?
아무튼 요래 쓰면 된다이!
빠르게 빌드해서 개발서버를 구축해 사용해볼수 있음
요래설정하고 npm run dev
하면 ts
로 작성된 파일을 뚝딱해준다! 참고로 스크립트에서 module
타입을 사용해야함.
오류를 잡아주는 eslint
와 포맷터인 prettier
도 사용해보자!
npm i -D eslint prettier eslint-plugin-prettier eslint-config-prettier @typescript-eslint/parser @typescript-eslint/eslint-plugin
하나씩 살펴볼까?
린트 설정은 아래와 같이한다
//.eslintrc.json
{
"extends":[
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended"
],
"parser": "@typescript-eslint/parser"
}
prettier설정은 입맛에 맞게 하면됨
근데 오류뜸. prettier의 개행방식과 윈도우의 개행방식 차이때문에...
.eslintrc.json파일에 이런 룰을 추가해주면 된다.
"rules": {
"prettier/prettier": [
"error",
{
"endOfLine": "auto"
}
]
}
운영체제에 맞게 개행문자 룰 적용
npm create vite@latest .
입력하면 환경에 맞게 패키지 뚝딱 가능!
와우!
근데 ts가 svg파일을 임포트하지 못한다
//custom.d.ts
declare module '*.svg' {
const content: any;
export default content;
}
이렇게 파일만들고 tsconfig.json
에 추가해주면 끝!
npm install
로 의존성 패키지 모두 설치후 npm run dev
입력하면
짜란~
환경설정이 간편하구나?
원시값, 객체, 배열 함수등 다 존재함.
const obj: {} = {};
obj.a =123 // 에러
a
라는 속성의 타입이 없어서 그렇다..! 그럼 a라는 속성의 타입을 넣어보겠다.
const obj: {a:number} = {}; //에러
obj.a = 123
a라는 프로퍼티 자체가 없어서 에러가 난다..다시 고쳐보자
const obj: {a:number} = {a:0};
obj.a = 123
이렇게 사용하면 에러가 나지 않는다. 굉장히 귀찮은 일이 아닐수 없다.
튜플은 TS에만 존재하는 타입으로 길이, 요소의 타입이 정해져있어야한다.
const arr : [] = [];
arr[0] = 123//에러
배열에 타입을 넣지않아 튜플타입이어서 타입이 정해져 있지 않은 공간에 123인 넘버를 넣을 수 없음
const arr : number[] = [];
arr[0] = 123
이건 넘버 배열타입이다. 문자열이 들어오면 에러를 뿜는다.
const arr: Array<number> = [];
위의 패턴과 동일하다.
const func: (msg: string) => string = (msg) => msg
매개변수와 리턴하는 값의 타입을 지정해주어야한다.
타입을 지정할때도 순서만 잘 맞춰주면 된다.
ES2015이후 JS를 사용하려면, tsconfig.json
에서 설정해주어야한다. 디게 귀찮구만!
//tsconfig.json
"compilerOptions":{
...
"target":"ES2015",
"lib" :["ESNext", "DOM", "DOM.Iterable"];
}
이러면 findIndex
같은 배열 메서드를 사용할 수 있게된다.
배열-객체를 합쳤다고 볼 수있다.(역방향 매핑)
enum Week {Sun, Mon, Tue, Wed, Thu, Fri, Sat};
Week[0] // Sun
Week[Sun] // 0
이렇게 사용할 수도 있다
enum Colors {Red, Green = 4, Blue}
Colors[red] // 0
Colors[Green] // 4
Colors[Blue] // 5
값을 명시적으로 지정해주면 이후 값들은 지정값+1부터 시작한다!
그럼 이렇게하면 어떻게 될까?
enum Colors {Red = "r", Green = 4, Blue = 7}
Colors[red] // r
Colors[Green] // 4
Colors[Blue] // 7
Colors.r // 에러
역방향 매핑은 숫자타입만 가능하다!정확히는 0이상의 정수겠지?
TS에선 return
키워드를 사용하지 않으면 void타입이 반환된다.
따라서 리턴문 없이 사용한다면 void타입을 지정해주어야함
const tup: [number, number] = [4,5]
tup[2] = 6//에러
튜플은 고정길이에 요소마다 타입이 정해져있음.
어떤 것도 할당할 수 없는 타입(...???)
정상적으로 종료되지 않는 함수가 반환하는 타입.
예를들어 Promise.reject
라던가...함수 예외처리중throw Error
로 나왔을때 라던가!
명시적으로 불가능을 나타내기 위한 타입이다.
어떤 것이든 할당 가능한 타입! 마치 바닐라 JS같구나.
사용을 아주 지양하는게 좋겠구먼? TS의 장점이 사라지니..
어떤 것도 할당할 수 있지만 정확히 무엇인지 알 수 없는 타입.
예?
참고로 any
는 다른타입에 할당 가능하지만 얘는 불가능하다. 얘가 좀 더 안전하구나?
아마 외부에서 받아오거나 여러 타입이 섞여있을때 사용할 것 같다!
타입을 2개 이상 허용하는 타입이다!
let uni: string | number
그냥 or
문 사용한거자나...? 🤨
2개 이상의 타입이 병합된 타입! 유니온과 뭐가 다를까?
type UserA = {
name: string,
age: number,
}
type UserB = {
isValid: boolean
}
const userA: UserA & UserB = {
name:"A", age:12, isValid: true
}
객체 내부의 타입을 짬뽕해서 사용할 수 있다는 걸까?
참고로 같은 프로퍼티를 갖고있다면 하나만 남게된다.
TS는 타입이 정해져있지 않다면 타입을 이렇게 추론한다.
어! 이거 저번 고양이사진첩 과제때 만들었던 validateState
함수와 비슷하군!
초기상태에 할당되어있는 변수의 타입과 다음 상태의 타입을 비교했었다.
=> 무조건 타입을 적지 않아도 된다. validateState
에서 사용한 것처럼 초기상태에 타입(문자열이면 빈 문자열 등)만
잘 할당해준다면 된다!!
아이디어는 고만고만하구먼ㅎㅎㅋㅋ
타입을 딱 잘라 말한다. 말만 들으면 선언과 다른점이 없어보이는데, 뭐가 다른걸까?
const button = document.querySelector('button');
button.classList.add('btn') // null일수도 있어서 에러
아...그렇구나. 여러 타입으로 존재할 수 있는 변수는 단언해줘야 오류가 나지않는다.
const button = document.querySelector('button') as HTMLButtonElement;
button.classList.add('btn')
//const button = document.querySelector('button')!
//위와같이 느낌표를 붙여 처리해줘도 좋다. null, undefined는 아니라는 소리다
음...그래도 예외처리는 필요할 것 같다. 강사님께선 타입 가드로 처리하신다는데, 나중에 배운다!
function foo(val: number | string, isNum: boolean){
if(isNum){
// val.toFixed(2). 숫자도 올 수 있지만 문자도 올 수 있어서 오류가 난다.
(val as number).toFixed(2) // 숫자로 단언하였기에 오류가 나지 않는다.
} else {
(val as string).slice(0,2)
}
}
JSON을 파싱할때도 주의해야한다.
값 선언 후 초기화 하지 않으면 undefined
할당이기에 타입을 지정할 시 초기화 해주는게 좋다.
안되는 상황이라면 !
단언연산자를 사용하면 된다!
let num!: number
console.log(num) // undefined
따로 기능이 있는건 아니고 오류가 나지않게 가드처리해주는 것.
주로 typeof, instanceof, in
키워드를 사용해서 처리함.
//btn은 HTMLButtonElement or null임. js처럼 가드처리해도됨.
const btn = document.querySelector("button");
if(btn){...}
//typeof로 판단
function toTwoDeicmals(val: number | string){
if(typeof val === "number"){
val.toFixed(2);
} else {
val.slice(0,2);
}
}
TS의 typeof
는 좀 다르게동작하나? 싶기도하고...왜냐면 typeof
는 NaN, 배열, null
을 제대로판단하지 못한다.
흠!
모듈 import
할때 별칭을 as
키워드로 만들어준것처럼 타입에도 별칭을 붙여줄 수 있다.
type
키워드를 사용하여 선언한다. 지금까지 type
키워드를 사용한 부분들은 전부 별칭이다.
type MyName = string;
const name: MyName = 'hi!';
//제네릭에도 가능하다
type typeGeneric<T> = {
name: T;
};
//&키워드를 이용하여 '확장'가능하다. '상속'과는 다르다.
type type1 = {name:string};
type type2 = type1 & { age: number };
const test: type2 = { name: "kim", age: 85 };
이처럼 별칭은 상속이 불가능하기에 상속이 가능한 interface
를 주로 사용하는 것이 좋다.