최대한 간단 명료하게 설명하며, 일부 심플한 내용을 이해하기 위한 반복적인 상세한 설명은 하지 않는다.(시간낭비)
⇒ 1번 완독하신분들이 복습하기 위한 용도.
2012 MS 에서 발표한, JS 기반의 정적 타입 문법을 추가한 언어
→ 정적 타입의 컴파일 언어
타입 종류
- 문자, 숫자, Boolean
let str: string = 'hello world'
let num: number = 123
let bool: boolean = true
- 객체 타입의 기본 형태
// 파라미터가 필요하면, 파라미터 필수로 넣어야 함.
// 파라미터가 있다면, 기본값도 필수로 넣어야 함.
const obj: { a: number } = { a: 0 }
obj.a = 123
- 배열
배열의 기본은 튜플 타입 배열의 요소타입을 정해줘야 함. 2가지 형태의 배열 선언 방식이 있음.
// 선언 방식 1
const arr: number[] = []
arr[0] = 123
arr[1] = 456
arr.push(789)
// 선언 방식 2
const arr2: Array<string> = []
arr2.push('messi')
- 함수
JS 처럼, 변수에 함수를 할당가능.
// 파라미터 타입과 반환값 타입을 지정
const hello: (msg: string) => string = (msg) => {
return msg
}
// 바로 return 이면, 화살표
const hello2: (msg: string) => string = (msg) => msg
// 일반 함수 버전
const hello3: (a: string, b: number) => string = function (msg, xyz) {
// ...
return msg
}
// 매개변수에 직접 타입 할당하는 버전
const hello4 = function (msg: string, xyz: number): string {
// ...
return msg
}
- Enum 타입
enum Week {
Sun,
Mon,
Tue,
Wed,
Thu,
Fri,
Sat,
}
console.log(Week[0]) // 값 추출
console.log(Week.Sun) // 인덱스 추출
- void 타입 : 값을 반환하지 않는 함수의 반환 타입
undefined 가 아니고 void 를 반환 해야 한다. 따로 return 키워드를 사용하는게 아니면, => void를 반환한다.
const empty1: (msg: string) => void = (msg) => {
console.log('Hello ${msg}')
}
empty1('World!')
- 튜플 타입 : 고정된 길의 배열
const tup: [number, number] = [4, 5]
// 튜플 사용 예시 : 데이터 유형 고정화
const userA: [number, string, boolean] = [1, 'juno', true]
const userB: [number, string, boolean] = [2, 'evan', false]
const userC: [number, string, boolean] = [3, 'call', masury@gmail.com] // 이렇게 사용하면 안된다는 걸 의미
튜플도 마찬가지로 배열이기 때문에, splice 와 push 같은 배열에 변동을 일으키는 기능을 사용할수 잇는데, 이러한 코드는 런타임에서도 잡지 못하기 때문에 사용하지 말것을 당부한다.
- Never 타입
어떤 것도 할당할 수 없는 타입, 혹은 정상적으로 종료되지 않는 함수의 => 반환 타입.
const myError: (m: string) => never = (msg) => {
throw '에러 - ${msg}'
}
try {
myError('never 타입')
} catch (err) {
console.error(err)
}
- Any 타입 : 어떤 것도 할당할 수 있는 타입.
let anything: any = 'dfd'
const ace: string = anything
const blue: number = anything
const customer: boolean = anything
any 는 어디든 할당 가능 하다.. 그러나. 타입스크립트가 나오게된, 계기를 생각하면, any는 최대한 사용하지 않는게 좋다. any 를 자유롭게 사용할거면, 뭐하러 타입스크립트를 사용하나??
- Unknown 타입 : 어떤 것도 할당할 수 있지만, 정확히 무엇인지 알수 없는 타입
let unknown: any = 'dfd'
unknown = 123
unknown = { a: 'A' }
unknown = [1, 2, 3]
// Unknown 타입은, 다른 변수에는 할당할수 없음
// 타입 가드에 활용하면 좋음.
if (typeof unknown === 'string') {
// unknown 이 string 값일 때만, 아래 코드 실행
const achivement: string = unknown
}
그래서 어떤데이터가 올지 모르는 경우에는, any 타입보다는 unknown 타입을 많이 사용함.
Any vs Unknown
any 를 사용한 방식
let any: any = 'hello'
console.log(any.toUpperCase()) // 정상작동
any = 123
console.log(any.toUpperCase()) // 런타입 에러 발생
let unk: unknown = 'hello'
console.log(unk.toUpperCase()) // 정적 Error
unk = 123
console.log(unk.toUpperCase()) // 정적 Error
unknown 을 이용한 엄격한 타입 처리
let unk: unknown = 'hello'
if (typeof unk === 'string') { // 타입 string 경우에만
console.log(unk.toUpperCase())
}
unk = 123
if (typeof unk === 'number') { // 타입 number 경우에만
console.log(unk.toUpperCase()) // 정적 Error
}
- union 타입 : 2개이상의 타입이 허용되는 경우
let uni: string | number
let uni2: string | number | number[]
- intersection 인터섹션 타입 : 2개 이상의 타입이 병합되어 1개의 타입이 되는 경우
type UserA = {
name: string
age: number
}
type UserB = {
isValid: boolean
}
// 타입 합성
const userC: UserA & UserB = {
name: 'C', age: 31, isValid: true
}
타입 추론
타입 추론(Inference) : 어떠한 코드의 내용을 근거로 판단(추론)을 이끌어냄.
코드 상에 최소 1개 이상의 힌트는 있어야 한다.
(컴퓨터도 힌트가 있어야 추론이 가능하기에...)
lat age = 45 // number
const name = '강감찬' // string
코드를 보면서 스스로 생각하는 타입 추론도 연습해야 한다.
타입 추론은 굳이 설명이 없어도 될듯
타입 단언과 할당 단언
타입 단언(Assertion) : '단언'이란, 주저하지 않고 딱! 잘라 말하는 것.
=> 개발자가 TS 에게, "이 코드는 이거다!!" 라고 단언하는 것. 물론 인간이 단언하는 컴퓨터에게 단언 하는것 이기에, 사용하는데 신중을 기해야 함.
- as, ! (Not-Null 단언 연산자)
// as, ! (Not-Null 단언 연산자)
// case 1
// as 를 이용하여 HTMLButtonElement 라고 단언
const btn = document.querySelector('button') as HTMLButtonElement
btn.classList.add('btn')
btn.id
const btn2 = document.querySelector('button')! // null 아니다 라는것만 단언
btn2.classList.add('btn')
btn2.id
// case 2
function toTwoDecimals(val: number | string, isNum: boolean) {
if (isNum) {
;(val as number).toFixed(2) // isNum = true 경우, val 을 number 라고 단언
} else {
;(val as string).slice(0, 2)// isNum = false 경우, val 을 string 라고 단언
}
}
// case 3
const json = '{ "name": "Hero", "age":85 }'
// as 를 통해 명확한 객체 내용 단언 => (객체 내용은 ~ 로 구성되어 있다)
const user = JSON.parse(json) as {name: string, age: number}
// case 4
let num!: number // ! 붙힘으로써, null 도 undefind 도 아니라는 것을 명시
console.log(num)
타입 가드
타입 추론이 가능한 특정 범위(scope) 안에서 타입을 보장
- typeof
- instanseof
- in
단언은 런타임시 에러발생을 시킴 (null 될수도 있음)
→ 타입가드를 통해 훨씬더 안전하게 코딩하자
// case 1
const btn = document.querySelector('button')
if (btn) { // btn 이 null 아닌 경우
btn.classList.add('btn')
btn.id
}
// 좀더 명시적으로
if (btn instanceof HTMLButtonElement) { // btn 이 HTMLButtonElement 인 경우만
btn.classList.add('btn')
btn.id
}
// case 2
function toTwoDecimals(val: number | string) {
if (typeof val === 'number') { // typeof 를 사용
val.toFixed(2)
} else {
val.slice(0, 2)
}
}
아래는 조금 복잡하지만 유용한 형태
// case 3
type UserA = {
name: string
age: number
}
type UserB = {
id: string
email: string
}
// 타입가드가 목적인 함수 isUserA
function isUserA(user: unknown): user is UserA { // user 이 UserA 인가? 라는 의미를 반환(boolean)
if(user && user.constructor === Object) {
const u = user as UserA
return typeof u.name === 'string' && typeof u.age === 'number' // UserA 이면 true 반환
}
return false
}
fetch('<https://exam.site>')
.then(res => res.json())
.then((user: UserA | UserB) => {
if(isUserA(user)) { // UserA 이면 true
console.log(user.name[0])
console.log(user.age - 10)
}
})
타입 별칭(Alias)
새로운 타입 조합 생성
type MyTypeName = string | number // MyTypeName 은 string , number 일수도 있다는 의미
type MyArray = MyTypeName[] // string , number 로 이뤄진 배열
type UserA = {
name: string
age: number
}
type UserB = {
isValid: boolean
}
type UserX = UserA & UserB // 2개를 병합한 UserX
// 위의 type을 이용한 예시
const a: MyTypeName = 'A'
const b: MyArray = [1, 'a', 'b', 5, 7]
const userA: UserA = {
name: 'koko',
age: 78,
}
const userB: UserB = {
isValid: false,
}
const userX: UserX = {
name: 'jaja',
age: 99,
isValid: true,
}
내가 자주사용하는 나만의 Type 생성
타입스크립트 인데, 의외로 이부분에서는 자유도를 부여한다.(생산성을 높이려는 의도)