이펙티브 타입스크립트 스터디 - 5주차 발표 정리
주제: 5장 any 다루기 (아이템 42 ~ 44)
아이템 42. 모르는 타입의 값에는 any 대신 unknown을 사용하기
함수의 반환값과 관련된 형태
function parseYAML(yaml: string): any {
// ...
}
interface Book {
name: string
author: string
}
const book: Book = parseYAML(`
name: Wuthering Heights
author: Emily Brontë
`)
만약, 함수의 반환 타입을 any로 설정했다면 사용하는 쪽에서 함수의 반환 타입을 따로 설정을 해줘야한다.
const book = parseYAML(`
name: Wuthering Heights
author: Emily Brontë
`)
book.title // 오류 없음, 런타임에 undefined 경고
만약, 설정을 안해준다면 위와 같다.
function safeParseYAML(yaml: string): unknown {
return parseYAML(yaml)
}
이런 경우는 함수의 반환타입을 any보다 unknown으로 명시하는 것이 더 안전하다.
any는 어떠한 타입이든 any에 할당이 가능하고, any는 어떠한 타입으로도 할당이 가능한 타입이다.
반면, unknown은 어떠한 타입이든 unknown에 할당이 가능하지만 그 반대의 경우는 만족하지 않는다.
즉, unknown은 어떠한 타입으로도 할당이 가능하지 않다. 오직 unknown, any에만 할당 가능하다. (never 타입은 반대이다)
이를 이용하여, unknown 타입을 사용하면서 적절한 타입을 명시하도록 유도할 수 있다.
function safeParseYAML(yaml: string): unknown {
return parseYAML(yaml)
}
const book = safeParseYAML(`
name: Villette
author: Charlotte Brontë
`) as Book
book.title // Book 형식에는 title이 없다는 에러
변수 선언과 관련된 형태
function processValue(val: unknown) {
if (val instanceof Date) {
val // Type is Date
}
}
타입 단언 뿐만 아니라 조건문을 걸어 원하는 타입으로 변환이 가능하다.
제네릭을 사용할 수도 있지만, 권유되지 않는 방법이다.
따라서, unknown을 사용한다면 직접 단언문을 사용하던가 원하는 타입으로 좁히는 것이 옳은 방법이다.
단언문과 관련된 형태
let barAny = foo as any as Bar
let barUnk = foo as unknown as Bar
any와 unknown의 차이는 unknown의 경우 타입스크립트가 타입에 대한 오류를 더 자주 발생시켜 타입에 대한 안전성을 더 갖춘다는 점이다.
이러한 이유만으로도 any보다 unknown을 사용하는 것이 나은 방법이다.
{}, object 타입
unknown보다는 좁은 타입이지만, unknown 만큼 넓은 타입을 가진 타입이다.
- {} 타입은 null과 undefined를 제외한 모든 값을 포함한다.
- object 타입은 모든 비기본형 타입으로, true 또는 12 또는 'foo'는 포함되지 않지만 객체와 배열은 포함한다.
{}는 거의 사용하지 않는다.
만약, null과 undefined가 불가능하다고 판단되는 경우에만 unknown 대신 {}를 사용하는 것을 고려해볼만 하다.
아이템 43. 몽키 패치보다는 안전한 타입을 사용하기
타입스크립트는 Document나 HTMLElement의 내장 속성에 대한 타입을 알고 있지만, 새롭게 추가한 값에 대해서는 알지 못한다.
이럴때는 any 단언문을 통해 해결할 수 있다.
(document as any).monkey = 'Tamarin'
하지만, 이렇게 선언하게 되면 타입 체커는 통과하지만 타입스크립트를 사용하지 않는 것과 마찬가지이다.
document 또는 DOM으로부터 데이터를 분리하는 것을 고려해보자.
1. 인터페이스의 특수 기능 중 하나인 보강 사용
interface Document {
monkey: string
}
document.monkey = 'Tamarin' // OK
타입이 더 안전하다는 장점이 있다.
하지만, 보강은 전역적으로 적용이 되기 때문에 코드의 다른 부분이나 라이브러리로부터 분리할 수 없다.
2. 더 구체적인 타입 단언문
interface MonkeyDocument extends Document {
monkey: string
}
확장의 개념이므로 Document 타입을 건드리지 않고 별도로 새로운 타입을 만들었기 때문에 분리가 가능하다.
아이템 44. 타입 커버리지를 추적하여 타입 안전성 유지하기
noImplicitAny를 설정해도 모든 any 타입 관련 문제들로부터 안전하다고 볼 수 없다.
다음의 경우도 고려를 해봐야 한다.
명시적 any 타입
any 타입의 범위를 좁히고 구체적으로 만든다 한들 여전히 any 타입이 존재할 것이다.
서드파티 타입 선언
@types 선언 파일로부터 any 타입이 전파될 수 있으니 주의해야함.
npx type-coverage
type-cover-age 패키지를 통해 프로젝트 내의 any를 추적할 수 있다.
npx type-coverage --detail
끝에 detail을 작성하면 any 타입의 위치도 출력할 수 있다.
프로젝트를 진행하면서 어쩔 수 없이 any를 사용해야할 때가 있다.
하지만, 꼭 나중이라도 any의 타입은 제거하는 것을 추천한다.
'프로그래밍언어 > TypeScript' 카테고리의 다른 글
이펙티브 타입스크립트 스터디 - 7주차 발표 정리 (0) | 2024.06.22 |
---|---|
이펙티브 타입스크립트 스터디 - 6주차 발표 정리 (1) | 2024.06.16 |
이펙티브 타입스크립트 스터디 - 4주차 발표 정리 (0) | 2024.06.01 |
이펙티브 타입스크립트 스터디 - 3주차 발표 정리 (0) | 2024.05.25 |
이펙티브 타입스크립트 스터디 - 1주차 발표 정리 (0) | 2024.05.11 |