https://www.typescriptlang.org/play?strictFunctionTypes=false#example/soundness
건전성은 컴파일러가 런타임 값이 컴파일 타임과 런타임에 같은 타입임을 보장할 수 있다는 것을 의미합니다.
1. Type assertions
const usersAge = ("23" as any) as number;
타입스크립트는 타입 단언을 통한 추론 오버라이딩을 허용합니다.
이는 당신이 타입스크립트보다 타입을 더 잘 알고 있으며, 해당 타입을 적용하는 것에 당신이 책임지는 것에 동의하는 것을 의미합니다.
건전한 언어들을 종종 런타임에도 타입을 검사합니다.
하지만 타입스크립트는 런타임에 타입 체크를 하지않는 것을 목표로 합니다.
타입 건전성 확보하기
1. 타입 단언보다 타입 선언 사용하기.(:Type)
2. 생성자 함수 등을 이용하여 런타임 타입 체크 밋 타입 생성 활용
3. 모나드 활용(Optional)
4. 꼭 써야 하는 경우에만 활용하기 (API리턴값, JSON.parse와 같은 any, DOM 접근)
(주 : 코드 레벨에서 해당 타입이라는 것을 체크해주기만 하면 타입 건선성은 유지된다.)
2. Function Parameter Bi-variance(이분산)
함수의 매개변수가 매개변수 재정의를 지원하는 경우입니다.
interface InputEvent {
timestamp: number;
}
interface MouseInputEvent extends InputEvent {
x: number;
y: number;
}
interface KeyboardInputEvent extends InputEvent {
keyCode: number;
}
function listenForEvent(eventType: "keyboard" | "mouse", handler: (event: InputEvent) => void) { }
매개변수 타입을 하위 타입으로 다시 선언할 수 있습니다.
위에서 핸들러는 InputEvent 유형을 예상했습니다.
그러나 아래 사용 예에서 - TypeScript는 추가 속성이 있는 타입을 허용합니다.
listenForEvent("keyboard", (event: KeyboardInputEvent) => { });
listenForEvent("mouse", (event: MouseInputEvent) => { });
// 이것은 최소 공통 타입을 허용합니다. (다운캐스팅)
listenForEvent("mouse", (event: {}) => { });
// But no further: 하위 유형이 아니기 때문입니다.
listenForEvent("mouse", (event: string) => { });
해당 오류는 strictFunctionTypes을 통해 해결할 수 있습니다.
그러면 함수 파라미터가 반공변(contravariance-상위타입 허용)을 허용합니다.
재밌게도 리턴 타입은 공변(covariant-하위타입 허용)입니다.
type F<T> = (p: T) => T
인자(Parameter)는 반공변성 흐름을 가지고,
반환(Return)은 공변성 흐름을 가지기 때문에 F<A> 와 F<B> 간에 어떤 형태의 Type Cast 도 일어날 수 없다.
T => T 는 무공변성(Invariance) 일 수 밖에 없다.
Type Cast 까지 고려를 한다면 반공변성 문제로 인해서 type F<P, R> = (p: P) => R 이 되어야만 한다.
type A = {a: string};
type B = {a: string, b: string};
type C = {a: string, b: string, c: string};
type F<P, R> = (p: P) => R;
const a: A = {a: 'a'};
const b: B = {a: 'a', b: 'b'}; // A는 B의 슈퍼타입
const c: C = {a: 'a', b: 'b', c: 'c'}; // B는 C의 슈퍼타입.
const faa: F<A, A> = (p: A) => a;
const fab: F<A, B> = (p: A) => b;
const fac: F<A, C> = (p: A) => c;
const fba: F<B, A> = (p: B) => a;
const fbb: F<B, B> = (p: B) => b;
const fbc: F<B, C> = (p: B) => c;
const fca: F<C, A> = (p: C) => a;
const fcb: F<C, B> = (p: C) => b;
const fcc: F<C, C> = (p: C) => c;
const fa1: F<C, A> = faa; // 인자의 반공변 (슈퍼타입 허용 - C의 슈퍼타입인 AB 다허용)
const fa2: F<C, A> = fab; // 리턴타입의 공변 (서브타입 허용 - A의 서브타입인 BC 다허용)
const fa3: F<C, A> = fac;
const fb1: F<C, A> = fba;
const fb2: F<C, A> = fbb;
const fb3: F<C, A> = fbc;
const fc1: F<C, A> = fca;
const fc2: F<C, A> = fcb;
const fc3: F<C, A> = fcc;
const list: F<C, A>[] = [
faa,
fab,
fac,
fba,
fbb,
fbc,
fca,
fcb,
fcc,
];
나머지 매개변수(Rest Parameter)
function getRandomNumbers(count: number, callback: (...args: number[]) => void) { }
getRandomNumbers(2, (first, second) => console.log([first, second]));
getRandomNumbers(400, (first) => console.log(first));
보이드 리턴 함수 타입은 다른 타입을 리턴하는 함수를 허용합니다.
주 : 이는 주로 콜백 형태로 함수를 넘겨 combinator 역할을 하는 함수의 리턴값을 사용하지 않는 경향이 있는 js의 특성을 반영한 허용임
const getPI = () => 3.14;
function runFunction(func: () => void) {
func();
}
runFunction(getPI);
참고 :
https://www.typescriptlang.org/docs/handbook/type-compatibility.html
https://dev.to/codeoz/how-i-understand-covariance-contravariance-in-typescript-2766
'FrontEnd' 카테고리의 다른 글
타입스크립트 타입 호환성과 타입 계층 트리 (0) | 2022.03.27 |
---|---|
아폴로 클라이언트로 알아보는 클라이언트 아키텍처 [Apollo Client & Client-side Architecture Basics] (0) | 2022.03.27 |
타입스크립트의 타입 불건전성에 대하여 1 : 타입시스템의 한계 (0) | 2022.02.25 |
Context API와 React.memo (0) | 2022.02.14 |
Context API(컨텍스트API)는 Dependency Injection(의존성 주입) 수단이다. (1) | 2022.02.11 |