인프런 타입스크립트 기초를 통해 공부중이며 제로초님의 유료강좌입니다.
코드를 통으로 가져오지는 않겠습니다.(내가 글을 쓰면서 복습하는게 목적이기때문에 필요한 부분만)
타입스크립트에 익숙하지않다면 자바스크립트로 먼저 코드를 작성하고 그 후에 타입스크립트로 변환하도록하자.
타입스크립트 (Typescript)
오 드디어 강의가 거의 끝이 나 보인다.!!!!
강의보고 이해하고 글한번 적고,, 다른것도 하다보니 되게 오래걸렸다.
다보고나면 뭐 하나 만들어보고 간단히 강의 훑고 react랑 typesctipt 같이 써봐야지!
진짜 의식의 흐름대로 글을쓰다보니 1회차부터 보니까 ㅋㅋㅋ 내가 헷갈림..ㅎㅎ
나중에는 공식문서보면서 좀 제대로 알아봐야겠다.
Typescript를 지원하는 패키지, 아닌 패키지
일단 typescript로 제작된 패키지도 있고 아닌애들도 있는데, redux같은 경우에는 typescript로 되어있어서 가져다쓰기 좋다고한다.
redux git에 가서 보면 이렇게 Typescript로 작성되었다는 것을 알 수 있다.
DefinitelyTyped
만약 내가 쓰려는 패키지가 Typescript로 작성되어있지 않다면 definitelyTyped를 이용하자.
https://github.com/DefinitelyTyped/DefinitelyTyped
이 레퍼지토리는 많은 사람들이 모여서 지원안하는 패키지의 type을 만들어둔 곳이라고한다.
공식적으로 지원하는 것이 없을 경우 여기서 찾아보면된다고!
유명하지 않은 패키지같은 경우에는 없을 수도 있다고 한다.
types 폴더에서 react나 jQuery들을 확인할 수 있다.
install하는 방법은 cmd 창에 @types/ 로 시작하면된다.
npm i @types/jquery
Triple Slash
패키지를 다운로드 받고 나면 d.ts파일에 아래와 같은 코드를 확인할 수 있는 경우가 있다.
이 경우는 다른 패키지를 참조하는 것을 나타내는데, 속성 값으로는 types와 path가 있다.
types에는 패키지의 이름을 적을 수 있고, path에는 경로를 적을 수 있다.
아래 코드와 같이 적혀있는 경우에는 symbol-observable을 참조하고 있다는 뜻이다.
/// <reference types="symbol-observable" />
왜 import를 안하냐고 할 수 있는데, import도 가능하나 다른 패키지를 참조할때는 저렇게 사용한다고 한다.
보통 프로젝트 코드가 아닌 라이브러리를 만들때 사용한다고 한다.
Namespace
export as namespace d3;
namespace는 export한 것들을 d3라는 네임으로 묶어주는 것을 뜻한다.
export as namespace d3;
export * from 'd3-array';
export * from 'd3-axis';
아래와 같이 되어있다면 d3-array에 export한 함수중에 max라는 함수가 있다면 아래와 같이 접근 할 수 있다.
d3.max
import * as
import하자마자 export한다는 뜻이다.
import * as d3 from 'd3';
declare
타입이 없는 것을 새로 선언할 경우에 사용할 수 있다.
types라는 폴더를 생성하고 그 아래 d.ts파일을 생성하여 아래와 같이 can-use-dom 패키지의 d.ts파일을 생성해 줄 수 있다.
// d.ts 파일
declare module 'can-use-dom'{
const canUseDOM: boolean;
export default canUseDOM;
}
// config 파일
{
"compilerOptions" : {
"strict" : true,
"lib" : ["EX5", "ES2015", "ES2017", "ES2018", "ES2019"],
"typeRoots" : ["./types", "./node_modules/@types"]
},
"exclude" : ["*.js"]
}
types는 내가 만든 파일이 들어있는 폴더의 경로이며 node_modules는 definitelyTyped에서 받은 d.ts파일들이 있다.
아래와 같이 다양한 작업을 할 수 있다.
전역 객체 선언
export{}
declare global{
interface Window{
//...
}
interface Error{
//...
}
}
export{}를 한 이유는 글로벌인 경우 external모듈이어야하기 때문에(규칙) export를 사용하여 꼼수로 에러가 안나도록한다.
글로벌 객체를 확장하기 위해서는 external, ambient 모듈이어야한다.
아래처럼 ambient 모듈로 만들어도된다. namespace, interface를 통해 express의 request를 확장할 수 있다.
declare module 'connect-flash'{
global {
namespace Express{
interface Request{
//...
}
}
}
}
import express = require('express');
(모듈관련해서는 좀 더 자세히 알아봐야할 듯 싶다)
잘못된 d.ts파일이라면?
1.먼저 패키지 d.ts파일을 install해서 복사해준다.
// 예시는 connect-flash 모듈
npm i @types/connect-flash
2.패키지를 제거한다.
npm rm @types/connect-flash
3.내가 작성하려는 d.ts파일을 모아둔 폴더에 빈 파일을 생성하여 붙여넣는다.
4.잘못된 부분만 수정한다.
d.ts파일 옵션 - 라이브러리 만들때 사용하는방법
// config 파일
{
"compilerOptions" : {
"strict" : true,
"lib" : ["EX5", "ES2015", "ES2017", "ES2018", "ES2019"],
"typeRoots" : ["./types", "./node_modules/@types"],
// 옵션추가
"declaration" : true,
"declarationDir" : "./types"
},
"exclude" : ["*.js"]
}
그 후 npx tsc 하게되면 declarationDir 경로에 d.ts파일을 자동으로 생성해준다.
intersection
& 이것을 말한다.
둘다 만족하는 것을 뜻한다.
type A = string & number;
예제
interface A {
a : true
};
interface B{
b : false
};
const c: A & B = {
a: true,
b: false
}
interface나 type aliases에서 사용할 수 있다.
interface A {
a : true
};
interface B{
b : false
};
type C = {
c : false
}
const d: A & B & C= {
a: true,
b: false,
c: false
}
|는 하나만 만족해도된다.
interface A {
a : true
};
interface B{
b : false
};
const c: A | Bㅌ= {
a: true,
b: true
}
코드의 중복을 막고 각각의 변수를 재사용하기 위해 좋다.
call, bind, apply
타입추론이 잘 안되는 메서드들이다.
타입스크립트가 업데이트되면서 새로운 옵션이 생겼다고 한다.
// config 파일
{
"compilerOptions" : {
"strict" : true,
// 옵션 추가
"strictBindCallApply" : true,
"lib" : ["EX5", "ES2015", "ES2017", "ES2018", "ES2019"],
"typeRoots" : ["./types", "./node_modules/@types"],
"declaration" : true,
"declarationDir" : "./types"
},
"exclude" : ["*.js"]
}
타입스크립트가 엄격해진다고한다.
TS유틸리티
Partial
// interface의 일부만 가져다가 사용할 때 사용한다.
interface A {
a: 'a',
b: 123
}
const a: A = {
a: 'a',
b: 123
};
// b가없어도 에러가 나지 않는다.
const b: Partial<A> = {
a: 'a'
}
Readonly
// 하나하나 넣어주면 너무 비효율적
interface A{
readonly a: 'a',
readonly b: 'b',
readonly c: 'c'
};
// Readonly
interface B{
a: 'a'
};
const b: Readonly<B> = {
a: 'a'
}
그 외에 공식문서보고 쭉 읽어보자.
pick, omit 등..
데코레이터
클래스나 클래스의 기능을 수정할 수 있다.
중복되는 코드가 생겼을때 함수를 하나 만들어서 사용할 수 있다.
아직 정식 문법이 아니어서 옵션 값을 추가해준다.
// config 파일
{
"compilerOptions" : {
"strict" : true,
"strictBindCallApply" : true,
"lib" : ["EX5", "ES2015", "ES2017", "ES2018", "ES2019"],
"typeRoots" : ["./types", "./node_modules/@types"],
// 옵션 추가
"experimentalDecorators" : true,
"declaration" : true,
"declarationDir" : "./types"
},
"exclude" : ["*.js"]
}
위에 적으면 클래스 데코레이터
메서드 옆에적으면 메서드 데코레이터라고 한다.
프로퍼티에 적으면 프로퍼티 데코레이터, 파라미터 옆이면 파라미터 데코레이터가 된다고 한다.
@makeGender
class Person{}
class Person{
@validate title : string
}
// typeof Person안하고 Person만 적으면 인스턴스가 되버려서 꼭 typeof Person해야한다.
function makeGender(target: typeof Person){
// 원본을 인자로 받아서 새로운 것을 extends 시켜서 내보낸다.
return class extends target{
//...
}
}
@makeGender
class Person{
//....
}
@makeGender
class Person2{
//....
}
데코레이터의 각각의 위치에 따라서 매개변수가 달라진다고 한다.
3번째 인자 값이 달라진다.
// 클래스 데코레이터
function readonly(target: any, key: any, descriptor: propertyDescriptor){
//....
}
// 파라미터 데코레이터
function readonly(target: any, key: any, index: number){
//....
}
Q&A 타입스크립트는 왜써요?
노드로 개발할 경우 서버가 죽는 경우가 생긴다.
보통어이없는 실수가 대부분이다.
타입스크립트는 코드 작성 시 에디터에서 한번 걸러주고 빌드시 두번 걸러줘서 안정성이 올라갈 수 있다.
자바스크립트는 런타입에서 오류가 나야 알 수 있다.
퍼포먼스가 좋아지는 일은 없다.
안좋아지는 일도 없다 빌드하는 시간이 걸리기는 하지만 컴파일된 코드를 런타임에서 실행하기 때문에 퍼포먼스에는 이상이 없다.