네카라쿠배 프론트엔드 2기 동료들과 프론트엔드 스터디를 진행하기로 결정하여 이번주부터 이펙티브 타입스크립트 스터디를 진행하게 되어 정리한 내용을 올리게 되었습니다.
Github Organization 주소: https://github.com/FEonTheBlock
Repository 주소: https://github.com/FEonTheBlock/Effective-TypeScript
문법의 유효성과 동작의 이슈는 독립적인 문제이다.
즉, 문법이 맞지 않는다고해서 동작이 아예 안되는 것은 아니다.
타입스크립트는 타입 추론을 통해 타입을 알고, 타입 체커가 문제를 찾는다. (string을 추론을 통해 알고, toUpperCase메서드로 추론)(소문자 → 대문자)
// city의 타입을 string으로 추론하고
let city = 'new york city';
console.log(city.toUppercase()); // 에러 발생 -> toUpperCase()를 의미하는 것인지?
타입스크립트에서 타입 구문을 추가한다면 훨씬 더 많은 오류를 찾을 수 있다. → states
예시(state의 인터페이스나 타입을 정의함으로써 개발자의 의도대로 사용하게 만듦)
타입스크립트 타입 시스템은 자바스크립트의 런타임 동작을 ‘모델링' 하지만, 의도치 않은 이상한 코드를 감지하기도 함(타입 체커에 의해)
작성된 프로그램이 타입 체크를 통과하더라도 여전히 런타임에 오류가 발생할 수 있다.
const names = ['Alice', 'Bob'];
console.log(names[2].toUpperCase());
앞에서 배열이 범위 내에서 사용될 것이라 가정했지만 그렇지 않아서 문제 발생!
오류의 근본원인은 타입스크립트가 이해하는 값의 타입과 실제 값에 차이가 있기 때문!!(이해하는 값의 타입: name의 문자열 vs 실제 값: undefined)
타입스크립트를 제대로 사용하려면 아래의 2개 설정을 최소한이라도 설정하자.
"noImplicitAny": true, // 암묵적 any 금지(명시적으로 써줘야함)
"strictNullChecks": true, // null, undefined 타입 허용X
→ 쉽게하려면 그냥 strict
설정 ㄱㄱ
"strict": true,
타입스크립트 컴파일러의 2가지 역할
독립적으로 이루어짐!
타입스크립트가 할 수 있는 일과 할 수 없는 일
증분 빌드: 컴파일과 관련한 기록파일을 남겨둠으로써
tsc
가 필요한 것만 효율적으로 컴파일할 수 있도록 하는 기능
증분 빌드 참고사이트: https://elvanov.com/2524
JS가 덕 타이핑 기반(객체가 어떤 타입에 부합하는 변수와 메서드를 가질 경우 객체를 해당 타입에 속하는 것으로 간주!) 이라 TS또한 이를 그대로 모델링함
→ 그러나 이 때문에 문제가 발생하기도함
const d: C = { foo: ‘object literal’ } // OK!
console.log(d(일반객체) instanceof C) // false
TS의 타입은 항상 열려 있다.
any
타입을 사용하면 타입 체커, 자동완성 서비스를 무력화하며 개발경험을 나쁘게하고 신뢰도를 떨어트리므로 사용하는 것을 지양하자!
any
타입의 문제
any
타입이면 무시하게 됨)number
)를 인수로 받아 사용하는 함수(타입:any
)의 콜백함수 문제)타입스크립트 설치를 하면 다음 두가지 실행이 가능
타입스크립트 서버가 타입 추론을 어떻게 하는지 커서를 갖다대어 확인하는 것은 타입스크립트를 연마하기에 좋은 방법!
→ 이를 통해 타입들을 보면서 라이브러리가 어떻게 모델링 되었는지, 어떻게 오류를 찾아낼지 살펴볼 수 있다. 그러므로 타입 선언 파일을 찾아보면서 공부!
가장 작은 집합: never ⇒ 유닛타입(하나) ⇒ 유니온 타입(여러개)
타입 연산자는 값의 집합에 적용된다.
interface Person {
name: string;
}
interface Lifespan {
birth: Date;
death?: Date;
}
type PersonSpan = Person & Lifespan; -> name, birth, death 속성을 가지고있음
// 객체타입에서
keyof (A&B) = (keyof A) | (keyof B)
keyof (A|B) = (keyof A) & (keyof B)
extends는 부분집합에 해당한다.
Exclude는 일부타입을 제외하는데 사용되지만 그 결과가 적절한 타입스크립트 타입일때 유효!
타입스크립트의 심벌은 타입 공간이나 값 공간 중의 한 곳에 존재한다!
심벌이 타입으로 쓰이는지, 값으로 쓰이는지 구분하는 것이 중요!
class Cylinder {
radius = 1;
height = 1;
}
const calculateVolume = (shape: unknown) => {
// 값으로 사용된 부분
if(shape instanceof Cylinder) {
// 타입으로 사용된 부분
shape
shape.radius
}
}
위 예제에서 클래스와 이넘같은 경우 타입 혹은 값으로 사용될 수 있음
InstanceType: 생성자 함수의 인스턴스 타입을 타입으로 구성하는 것
객체의 프로퍼티 타입에 접근시 대괄호 표기법으로 접근!
✅ p: Person[’first’]
❌ p: Person.first
속성접근자
type Tuple = [string, number, Date]
// TupleEl의 타입은 string | number | Date
type TupleEl = Tuple[number] // number가 0, 1, 2 중 하나만 올 수 있으므로(그 의미로 쓰임) 어려움..
타입 공간과 값 공간의 혼동
function email({person: Person, subject: string, body: string}) {}
이렇게 작성하면 JS의 alias(별칭)으로 판단하여 타입이 값으로 쓰이기 때문에 오류가 발생한다. 따라서 아래와 같이 변경!
function email({
person,
subject,
body,
}: {
person: PresentationStyle;
subject: string;
body: string;
}) {}
타입 단언은 강제로 타입을 지정해서 타입체커에게 오류를 무시하라고 하는 것이기에 타입 선언 사용을 더 지향하자.
잉여 속성 체크(지정된 프로퍼티 이외에 다른 프로퍼티가 있는지 검사) 또한 타입 단언문에선 적용 X
타입 단언은 보통 DOM 엘리먼트를 가져올때 적용한다. (개발자가 더 잘 알고 있는 경우)
캡틴 판교는
null
단언문보다 dom에 단언문을 사용하는 것을 권장
// like this
function $<T extends HTMLElement>(selector: string) {
const element = document.querySelector(selector);
return element as T;
}
const confirmedTotal = $<HTMLSpanElement>('.confirmed-total');
타입스크립트는 기본형(원시타입)과 객체 래퍼타입을 별도로 모델링하기 때문에 값으로써 사용할 때와 타입으로 사용할 때를 구분하고, 타입으로 사용시 주의해야 한다!
// 이렇게 쓰지 말고
const s: String = 'primitive'; (x)
// 이렇게 쓰자! (기본형으로)
const s: string = 'prmitivie'; (o)