
타입스크립트 공부하면서 제가 이해하기 쉽게 정리했습니다만, 정신 놓고 읽다보면 여러분도 이해가 갈 거라고 생각합니다.
일종의 에디터 부가 기능 역할이라고 생각하면 될 듯요.
맛보기
var counter = 1
counter ='2'
// Error: 님 왜 숫자에 문자 넣어요?
어케 설치하냐
npm install -g typescript
에러가 난다면
(1) nodejs 최신버전 설치를 안한 것임 삭제 후 최신 버전으로 재설치 합시다.
(2) 윈도우인데 허가되지 않은 script 실행불가 어쩌구 에러가 뜨면
시작 - 검색 - powershell - 우클릭해서 관리자 권한으로 실행한 다음
Set-ExecutionPolicy Unrestricted 입력하셈 그리고 y 선택하면 될듯
(3) 맥북인데 보안에러 어쩌구가 뜨면
sudo npm install 어쩌구~ 이렇게 sudo를 앞에 붙여보십시오.
중간에 맥북 비번입력이 필요할 수 있습니다.
대부분 nodejs 설치 안 해서 나는 게 대부분이니 잘 확인합시다.
npm install --save typescript @types/node @types/react @types/react-dom @types/jest
npx create-react-app my-app --template typescript
node.js는 제발 최신버전 설치합니다.
tsconfig.json에 내용 적으삼
{
"compilerOptions": {
"target": "es5",
"module": "commonjs", // 근데 이거 쓰지마십쇼
}
}
ts-> js 컴파일 시 옵션 설정 가능한 tsconfig.json
target: 어떤 버전의 자바스크립트 문법으로
module: 자바스크립트 파일 간 import 문법을 구현 시 어떤 문법을 쓸지
자세한 건 이 글을 꼭 읽어보시고 선택하시길 바랍니다.
근데 정말 신버전 자바스크립트만 표현가능한 그런 문법들이 있는데 (예를 들어 BigInt() 이런 함수와 bigint 타입)
그런 것들은 esnext 등으로 버전을 올려줘야 사용가능합니다.
{
"compilerOptions": {
"target": "es5",
"module": "선택",
"noImplicitAny": true,
"strictNullChecks": true
}
}
noImplicitAny는 any라는 타입이 의도치않게 발생할 경우 에러를 띄워주는 설정이고
strictNullChecks는 null, undefined 타입에 이상한 조작하면 에러를 띄우는 설정입니다.
((이건 vite 등 빌드도구 안 쓸 때 사용합니다.))ts 파일을 js로 변환해야함
tsc -w 명령어 쳐놓으면 ts 만들면 자동으로 js 파일로 변환시켜줍니다.
저장할때마다 js파일 갱신시켜줘서 편합니다.
나중에 html에 꽂아야할 때 js파일 갖다 쓰면 됨
타입1 or 타입2 들어올 수 있는 변수
let 변수 : string | number = 123
이렇게 or로 써주면 string or number 타입이 이 변수에 들어올 수 있단 뜻입니다. 이제 저 변수엔 123, 혹은 '123'을 써도 타입스크립트가 안 혼냅니다.
그럼 만약에 [1, '2', 3] 넣고 싶어요 하면 어떻게 타입을 정해주냐?
일단 뭐 array부터 봅시다.
let 변수 : array 이런식으로 안 씁니다. 간단하게 [] 써줍시다.let 변수들 : [] = [1, '2', 3]
let 변수들 : (string | number)[] = [1, '2', 3]
이렇게 or 로 묶어주고 깔끔하게 괄호쳐서 만들어줍시다. 얘는 이제 string[] or number[]를 받을 수 있는 변수가 됐습니다.
➕ 번외로 tuple이란 게 있는데 그냥 줄세우기입니다.
number[number, string, number]하면 순서대로 들어와야함
function (param: type) : someType {...}
param 변수에 들어오는 파라미터는 type만 들어와야하고, () 뒤에 적어준 타입은 함수의 리턴값 타입입니다. 저 someType에 string을 적었다 하면 저 함수는 string만 반환하는 겁니다.
object를 볼까요
let object : {a: string} = {a : '123'} 혹은 a: 123을 넣고 싶다면
{a: string | number}하면 됩니다. 여기까지 이해가 안 간다면 그냥 왼쪽 오른쪽 짝맞추기라고 생각하십시오. 오른쪽에 문자열 썼으면 왼쪽에 string, 오른쪽에 숫자배열 들어가면 왼쪽에 number[]... 이런 식으로.
any도 있긴 한데요 타입실드 해제문법입니다.
그래서 타입관련 버그가 나도 잡아주지 않음. 좋다고 막 쓰면 안됩니다. 그럼 타입 관련 버그가 생길 경우 왜 그런지 추적하기가 어려우니까요. 타입 실드를 안 씌우면 타스를 쓸 이유가 없습니다. 다 들어갈 수 있거든요.
그래서 비상시 쓰는 변수 타입체크 해제기능 이런 용도로 씁시다.
최신버전에서는 unknown이 있는데 any랑 유사합니다.
let name : unknown
let example : string = name ❌
unknown 해놓으면 해당 변수를 다른 변수에 할당했을 때 안돼서 좀 더 안정적입니다. 그쪽 타입 실드(string)이 발동해서 에러가 납니다.
name = 123, name = [] 처럼 자료 집어넣어도 타입은 그대로 unknown입니다.
그래서 unknown 타입인 변수를 조작하려면 내가 조작할 변수의 타입이 무엇인지 확실하게 체크하는 narrowing 또는 assertion 스킬을 사용해야합니다.
그것이 타입스크립트의 근간이 되는 코딩방법이고...
변수에 뭐가 들어있을지 아직 모르는데 그 변수를 사용하고 조작해야하는 경우
narrowing 또는 assertion을 반드시 사용해야 에디터가 땡깡 부리지 않습니다.
나중에 알아봅시다.
let age : string | number
age + 1 ❌
나이 + 1 이건 왜 안되냐? 자스에서 +1은 문자열, 숫자 둘다 됩니다. 그래서 될 거 같은데 왜 안되냐 string 타입 + 1, number 타입 + 1은 됩니다. 근데 string 또는 number라는 union type은 안됩니다. union type은 string 또는 number라는 새로운 타입을 만들어낸겁니다. 그래서 안돼요.
let age :unknown = 1
이건 되겠지
안됩니다
타스는 엄격해서 number 등 숫자 타입이어야만 연산해줍니다. 숫자. 진짜 숫자.
type이 아직 하나로 확정되지 않았을 경우 사용해야합니다.
let age : string | number
애매하죠
if (age 타입이 string이면) {...}
else {...}
이렇게 해주는게 narrowing입니다 정말 쉽죠. 유효성 검사 같은 겁니다.
그럼 이걸 어케 하냐 대표적인 방법 3가지가 있습니다.
타입을 잠깐 덮어쓰는것
function (x: number | string) {
let array : number[] =[];
array[0] = x as number // x를 number로 집어넣어주세요
}
용도:
1. Narrowing할때 씁니다.
2. 타입을 a에서 b로 변경할 때 쓰는게 아니라 a or b 타입일때 하나 정해주는 겁니다.
as 키워드는 union type 같은 복잡한 타입을 하나의 정확한 타입으로 줄이는 역할을 수행합니다. (number 타입을 as string 이렇게 바꾸려고 하면 에러날걸요)
3. 무슨 타입이 들어올지 100% 확실할 때 (버그 추적하기 좀 그래서 굳이 쓸 이유가 없는...)
디버깅용 비상용으로...
다음 예를 한 번 봅시다.
function example(x : number | string) {
return (x as number) + 1
}
일 때 example('123') 하면 1231이 나옵니다. as는 그냥 주장만 하는거지 실제로 타입을 바꿔주진 않음.
as 쓰면 간편해쥬금 하지만 정확히 코드짜려면 narrowing을 씁시다.
as 키워드는 맘대로 타입을 개발자 맘대로 주장하는 역할이라 때문에 엄격한 타입체크기능을 잠깐 안쓰겠다는 뜻과 동일합니다.
그래서 as 문법은 이럴 때 쓰도록 합시다.
일반 글자 같은 것도 타입이 될 수 있습니다.
특정 글자나 숫자만 가질 수 있게 제한을 두는 타입을 literal type 이라고 부릅니다.
더욱 엄격한 실드라고 보면 되겠군요.
const name :'감자'
이라고 타입을 정해주면 이제 name에는 '감자'라는 이름의 타입만 들어갈 수 있슴다.
함수도 똑같습니다.
function 숫자만리턴하는함수(a: '숫자') : 1 | 0 | -1 {
return 1 // or 0 or -1
}
readonly입니다. 영어 그대로 읽기만 가능한 데이터입니다.
타스 쓰면 object 자료 수정도 막을 수 있습니다.
const boyFriend = {
name: '철수'
}
boyFriend.name = '짱구'
이러면 boyFriend.name 이 짱구로 바뀌겠군요.
type BoyFriend = {
readonly name: string
}
const boyFriend: BoyFriend = {
name: '철수'
}
boyFriend.name = '짱구' ❌
이러면 boyFriend.name ='짱구'가 안됩니다. 에러로 혼내줘요. 근데 또 에디터 & 터미널에서 에러만 띄워주는거라 실제 실행은 됩니다.
object 뽑는 기계일 뿐입니다.
var nunu = {
q:'consume'
w: 'snowball'
}
var garen = {
q: 'strike',
w: 'courage'
}
...
...
이렇게 object 여러개 똑같은 속성 가진 것들 100개 1000개 만들기 힘들고 귀찮으니 class하나로 퉁치자 이겁니다.
function Hero() {
this.q = 'consume'
this.w = 'snowball'
}
this는 머냐 이 함수로부터 새로 생성되는 object들(instance들이라고 합니다.)을 뜻합니다.
this.q는 새로 생성되는 인스턴스에 { q: 'consume' } 추가해주셈 이런 뜻입니다.
뽑아 쓸 때는 new Hero() 이렇게 new로 심봤다 하면 됩니다.
var nunu = new Hero()
근데 일케하면 nunu도 garen도 똑같은 q와 w를 갖게 됩니다. 우린 다르게 만들고 싶잖아요.
function Hero(파라미터) {
this.q = 파라미터
this.w = 'snowball'
}
var nunu = new Hero('consume') 이렇게 하면 넣고 싶은거 넣어서 원하는 속성에 넣을 수 있습니다.
근데 앞에서 한 거 다 잊어먹어도 ES6 신문법에선 class 문법과 contstructor를 쓰면 됩니다.
class Hero {
constructor(파라미터1, 파라미터2) {
this.q = 파라미터1
this.w = 파라미터2
}
}
class에서 타입스크립트랑 자바스크립트랑 다른 점이 하나 있습니다.
class Hero {
constructor(파라미터) {
this.name = 파라미터
}
}
자스에선 이렇게 constructor에만 넣어줘도 통과시켜주는데요 타스에선
class Hero {
name : string
constructor(파라미터: 타입) {
this.name = 파라미터
}
함수() {}
}
이렇게 Hero 안의 필드에 속성 값을 설정해주고 constructor에 써줘야합니다.
class 안에 함수도 집어넣을 수 있는데, Hero.prototype.함수() = function () {}와 같습니다. 그냥 클래스 안에 집어넣어서 생성해주면 돼요. 프로토타입은 여기 읽어보십쇼.
그래서 클래스를 왜 쓰냐?
비슷한 object들 쉽게 만들고 싶을 때 이런 문법 씁니다. 코드 양도 줄어들고요, 추상화 다형성 캡슐화 요런것들에 도움이 됩니다.
class는 뭔가를 물려주고 있잖아요?
Hero라는 부모가 자식에게 q,w를 물려줘서 자식도 q,w 를 쓸 수 있게 해주는...
이걸 prototype이라는 걸 써도 물려줄 수 있습니다.
Hero 를 콘솔에 찍어보면 숨겨져 있는 속성이 하나 있습니다.
Hero.prototype이라는 건데요.
prototype는 걍 유전자입니다. 부모가 줄 수 있는 유전자란 소립니다.
Hero.prototype.name = '감자'
하고 nunu.name을 쳐보면 '감자'가 출력됩니다. 근데 nunu 를 출력해보면 q와 w밖에 없어요.
class에 쓰면 자식이 직접 가지고 있는 속성들이고, prototype에 쓰면 부모만 가지고 있는걸 자식이 끌어다 쓰는 느낌입니다.
부모 유전자에 있는걸 자식이 사용가능한 이유는 nunu.name을 쳐서 nunu가 name을 가지고 있지 않다? 하면 부모까지 뒤져봅니다.
부모님 님 name가지고 있어요? ➡️ ㅖ ➡️ 주세요 name하고 갖고온다는겁니다
var array = [4,3,1]
array.sort()하면 정렬되잖아요. 이거에 대해서 궁금해해 본사람?
내가 따로 array안에 sort()라는 함수를 정의해주지 않았는데 가져다 쓸 수 있잖아요.
이게 생성시에 var array = new Array(4,2,1) 이런 식으로 내부적으로 new Array를 사용해 만들어주고, array.sort()를 했을 때 array 위에 부모한테 가서 sort를 가져와서 쓰는겁니다.
궁금하면 Array.prototype 페이지 콘솔창에 써봅시다.
MDN Web Docs에 가보면 여러가지 확인할 수 있는데 여긴 솔직히 맨날 느끼는건데 뭔 소린지 모르겟읍니다 암튼 이 사이트 보면 Array.prototype.sort()라고 돼있습니다. 이제 이해할 수 있겟져
많이들 어려워하는 나만어려운 interface
let 학생 = { name : '난 학생이고' }
let 선생 = { name : '난 선생이야' }
이런 변수가 있다고 해봅시다. interface는 type 선언과 비슷합니다. 한번 짜봅시다
interface Student {
name: string
}
interface Teacher {
name : string
age: number
}
let 학생 = { name : '난 학생이고' }
let 선생 = { name : '난 선생이야' age: 20 }
근데 Student와 Teacher에서 name이 겹치지 않습니까? 요 녀석들을 혼내줄 수 있습니다.
interface의 장점 중에 하난데요 extends로 복사가 가능하단 겁니다.
interface Student {
name: string
}
interface Teacher extends Student {
age: number
}
let 학생 = { name : '난 학생이고' }
let 선생 = { name : '난 선생이야' age: 20 }
이렇게 갖다 쓰면 위에 인터페이스 나눠서 각자 name 넣은거랑 똑같습니다. 참 쉽죠?
interface는 중복선언이 가능합니다.
type은 중복선언이 불가능합니다.
interface Student {
name: string
}
interface Student {
score: number
}
얘는 이제 Student가 { name: string, score: number } 을 갖게 됩니다. 자동으로 extends된다는겁니다.
extends 쓸 때 중복속성 발생하면 알아서 에러로 혼내줍니다.
type Student {
name: string
}
type Student {
score: number
}
타입은 이런거 안 됩니다.
interface는 유연하다, type은 엄격하다라고 생각하면 됩니다. 그래서 언제 쓰면 되는데?
대부분 interface 쓰면 됩니다. 추후에 타입 추가하는게 더 편합니다. 어떤 별칭으로 표기하고싶거나 합/곱 타입등이 필요하면 type alias 를 사용하면됩니다.
type의 extends? 느낌은 & 기호를 쓰면 object 두개를 합칠 수 있습니다. 이걸 intersection이라고 하는데요.
type Animal = {
name :string
}
type Cat = Animal & { legs: number }
// = { name: string, legs: number }
또는
type Name = string
type Age = number
type Person = Name | Age
// 이렇게 유니온으로 타입 합쳐줄 수 있음 = type Person = string | number
사실 interface도 intersection이 가능함
interface Student {
name :string,
}
interface Teacher {
age :number
}
let 누구세요 :Student & Teacher = { name : '난 선생이야', age : 90 }
기본적인 typescript의 특성은 이 정도면 된 것 같습니다.
다음은 declare, public, private, protected, static... 뭐 이런거 알아봅시다.
참고
코딩애플 - 타입스크립트 쓰는 이유 & 필수 문법 10분 정리
ASAC 강의 자료