✨ top 타입
top 타입은 시스템에서 가능한 모든 값을 나타내는 타입입니다.
any
any 타입은 top 타입처럼 작동할 수 있지만, 타입 검사를 수행하지 않도록 명시적으로 지시합니다. 즉 타입 오류를 보고하지 않습니다.
let anyValue: any;
anyValue = "ABC" // OK
anyValue = 123 // OK
function greet(name: any){
console.log(`hi ${name.toUpperCase()}!`)
}
greet({name: "ABC"}) // OK
unknown
unknown 타입은 진정한 top타입 입니다. 타입의 값을 제한적으로 취급합니다.
function greet(name: unknown){
console.log(`hi ${name.toUpperCase()}!`)
// ERROR 'name' is of type 'unknown'.
}
위 코드에서 unknown 타입에 접근하기 위해서는 instanceof 혹은 typeof 키워드를 통해 타입 어서션을 사용하여 타입을 제한하여야 합니다.
function greet(name: unknown){
if(typeof name === "string"){
console.log(`hi ${name.toUpperCase()}!`)
} // OK
}
✨ 타입 서술어
instanceof 혹은 typeof 구문을 사용해 타입을 좁힐 수 있지만, 로직을 함수로 감싸면 타입을 알 수 없게 됩니다.
function isString(value: unknown) {
return ['string'].includes(typeof value)
}
function greet(name: unknown){
if(isString(name)){
console.log(`hi ${name.toUpperCase()}!`)
} // ERROR 'name' is of type 'unknown'.
}
타입 스크립트에는 인수가 특정 타입인지 여부를 나타내기 위해 **boolean 값을 반환하는 함수를 위한 특별한 구문**이 있습니다. 이를 타입 서술어 라고 합니다.
이는 매개면수의 이름, is 키워드, 특정 타입으로 선언할 수 있습니다.
function isString(value: unknown): value is string {
return ['string'].includes(typeof value)
}
function greet(name: unknown){
if(isString(name)){
console.log(`hi ${name.toUpperCase()}!`)
} // OK
}
타입 서술어는 한 인터페이스의 인스턴스로 알려진 객체가 더 구체적인 인터페이스의 인스턴스인지 여부를 검사하는 데 자주 사용됩니다.
class Man {
strength: number
constructor(value: number) {
this.strength = value
}
}
class SuperMan extends Man {
isFly: boolean
constructor(value: number){
super(value)
this.strength *= 1000
this.isFly = true
}
}
function isSuperman(value: Man): value is SuperMan {
return 'isFly' in value
}
function isFlyPeople(value: Man) {
if(isSuperman(value)){
console.log(value.isFly) // OK
}
console.log(value.isFly) // ERROR Property 'isFly' does not exist on type 'Man'.
}
타입 서술어는 타입을 확인하는 것 이상으로 수행하는 것은 지양해야 합니다. 간단한 타입 서술어만으로도 충분합니다.
✨ 타입 연산자
keyof
자바스크립트는 string타입의 동적 값을 통해 멤버를 찾는 경우가 있습니다. 하지만 다음과 같은 경우는 에러가 발생합니다.
interface Ratings {
audience: number;
critics: number;
}
function getRating(rating: Ratings, key: string){
return rating[key]
/* ERROR
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Ratings'.
No index signature with a parameter of type 'string' was found on type 'Ratings'.
*/
}
이러한 경우 keyof 키워드를 사용할 수 있습니다.
interface Ratings {
audience: number;
critics: number;
}
function getRating(rating: Ratings, key: keyof Ratings){
return rating[key] // OK
}
keyof Ratings 는 audience | critics 타입과 동일하지만, 작성하기 빠르고 수동으로 업데이트 할 필요가 없습니다.
typeof
아래의 copy 변수는 original 과 동일한 타입 값을 가집니다.
const original = {
title : "ABC",
description : "ABCDE"
}
let copy: typeof original
keyof typeof
keyof는 타입에 허용된 키를 검색하고, typeof 는 값의 타입을 검색합니다.
두 키워드를 함께 사용하면, 작업할 때 매우 유용합니다.
const original = {
title : "ABC",
description : "ABCDE"
}
function logValues(key: keyof typeof original) {
console.log(original[key])
}
✨ 타입 어서션
타입 시스템을 100% 정확하게 알리는 것이 불가능한 상황이 있습니다.
JSON.parse 는 의도적으로 top타입인 any를 반환합니다.
타입 어서션을 이용하여 타입을 설정할 수 있습니다. as 키워드를 사용합니다.
const rawData = `["abc", "ABC"]`;
JSON.parse(rawData) as string[];
하지만 타입 어서션을 되도록 지양하세요.
포착된 오류 타입 어서션
오류를 처리할 때 타입 어서션이 매우 유용합니다.
try{
//...
} catch(error) {
console.log((error as Error).message)
}
일부 프로젝트에서는 문자열 리터럴 또는 다른 의외의 값을 발생시키기도 합니다. 따라서 내로잉 하는 것이 더 안전합니다.
try{
//...
} catch(error) {
console.log(error instanceof Error ? error.message : error)
}
non-null 어서션
이론적으로 null 또는 undefined를 포함할 수 있는 변수에서 null과 undefined를 제거할 때 타입 어서션을 주로 사용합니다.
let maybeDate = Math.random() > 0.5 ? undefined : new Date();
const thisMustDate = maybeDate as Date
// const thisMustDate: Date
!를 사용하여 전체타입 대신 작성할 수 있습니다.
const hashMap = new Map([
["ABC", "123"],
["DEF", "456"]
])
const valueOfABC = hashMap.get("ABC")
console.log(valueOfABC.toUpperCase()) // ERROR 'valueOfABC' is possibly 'undefined'.
const valueOfDEF = hashMap.get("DEF")!
console.log(valueOfDEF.toUpperCase()) // OK
타입 어서션 주의 사항
- 타입 어서션은 도피 수단의 하나입니다. 따라서 자주 사용해선 안됩니다. 확실히 안전한 상황에서만 사용하세요.
- 어서션과 선언은 다릅니다. 어서션은 타입 검사를 건너뛰도록 명시적으로 지시하는 것이고, 선언은 변수의 초기값에 대해 할당 가능성 검사를 수행합니다.
- 이중 타입 어서션을 사용하여 전혀 관련 없는 타입을 허용할 수 있습니다.하지만 이는 잘못된 코드의 징후입니다. 수정하세요.
- const myName = "lurgi" as unknown as number; // OK // const myName: number
✨ const 어서션
const 어서션은 배열, 원시 타입 값, 별칭 등 모든 값을 상수로 취급해야 함을 나타내는데 사용됩니다. 다음 규칙을 적용합니다.
- 배열은 가변 배열이 아닌 읽기 전용 튜플로 취급
- 리터럴은 일반적인 원시 타입과 동등하지 않고 리터럴로 취급
- 객체의 속성은 읽기 전용으로 간주
읽기 전용 튜플로 취급
const arr = [0, ""] // const arr: (string | number)[]
const arr2 = [0, ""] as const // const arr2: readonly [0, ""]
읽기 전용 객체
const obj = {
name: "lurgi"
} as const
obj.name = "ABC"
// ERROR Cannot assign to 'name' because it is a read-only property.
리터럴에서 원시 타입으로
const getName = () => "lurgi" // const getName: () => string
const getName2 = () => "lurgi" as const // const getName2: () => "lurgi"
다음과 같은 상황이 발생할 수 있습니다.
interface Style {
style : "style1" | "style2"
}
function printStyle(obj : Style){
if(obj.style === "style1"){
console.log("style1")
}
if(obj.style === "style2"){
console.log("style2")
}
}
const obj = {
style : "style1"
}
printStyle(obj)
/* ERROR
Argument of type '{ style: string; }' is not assignable to parameter of type 'Style'.
Types of property 'style' are incompatible.
Type 'string' is not assignable to type '"style1" | "style2"'.
*/
const obj2 = {
style : "style1" as const
}
printStyle(obj2) // OK
'기술 서적 > 하루 30분 러닝 타입스크립트' 카테고리의 다른 글
[하루 30분 러닝 타입스크립트] 선언 파일 (0) | 2024.01.30 |
---|---|
[하루 30분 러닝 타입스크립트] 제네릭 (1) (0) | 2024.01.17 |
[하루 30분 러닝 타입스크립트] 클래스(2) (0) | 2024.01.08 |
[하루 30분 러닝 타입스크립트] 클래스(1) (0) | 2024.01.07 |
[하루 30분 러닝 타입스크립트] 인터페이스 (0) | 2024.01.04 |