
자바스크립트 배열은 내용을 변경할 수 있기 때문에,
타입스크립트에서도 역시 오류 없이 통과하게 된다.
👀 오류 범위를 좁히기 위해서
readonly접근 제어자를 사용할 수 있다.
readonly 접근 제어자를 사용한 간단한 함수를 작성해봤다.

readonly가 뭐길래...? 메서드를 사용할 수 없는 이유가 뭘까?
오류 메시지는 아래와 같다.
Property 'pop' does not exist on type 'readonly number[]'.
→ 'readonly number[]' 형식에 'pop' 속성이 없습니다.
이 오류 메세지를 자세히 살펴보자.
readonly number[] 는 타입이고 number[]와 구분되는 몇 가지 특징이 있다.
number[]는readonly number[]보다 기능이 많이 때문에,readonly number[]의 서브 타입이 된다.따라서, 변경 가능한 배열을
readonly배열에 할당할 수 있다. 하지만 그 반대는 불가능하다.
아래 코드를 보면 그 뜻이 좀 더 이해갈 것이다.

The type 'readonly number[]' is 'readonly' and cannot be assigned to the mutable type 'number[]'
→ 'readonly number[]' 타입은 'readonly'이므로 변경가능한 'number[]'타입에 할당 될 수 없습니다.
매개변수를 readonly로 선언하면,
자바스크립트에서는(타입스크립트도 마찬가지) 명시적으로 언급하지 않는 한, 함수가 매개변수를 변경하지 않는다고 가정한다.
그러나 이러한 암묵적인 방법은 타입 체크에 문제를 일으킬 수 있다.
공통점 : const와 readonly는 초기 때 할당된 값을 변경할 수 있다.
변수 참조를 위한 것이다.
변수에 다른 값을 할당할 수 없다.
속성을 위한 것이다.

testB.testC에 새로운 값이 할당될 수 있는 이유는 readonly가 얕게 동작하는 것과 관련이 있다.
참조 (refer)하고 있는 값 자체는 변경될 수 없지만 안에 있는 속성들이 모두 동일한 접근 제어자를 가지고 있는 것이 아니다.
배열에 readonly가 존재한다고 배열 자체가 readonly가 되지 않는다.
interface ScatterProps {
// data
xs: number[];
xs: number[];
// display
xRange: [number, number];
yRange: [number, number];
color: string;
// events
onClick: (x: number, y: number, index: number) => void;
}
const REQUIRES_UPDATE: {[k in keyof ScatterProps]: boolean} {
// 매핑된 타입으로 ScatterProps 가 변경되면 REQUIRES_UPDATE 도 변경됨을 알림
xs: true,
ys: true,
xRange: true,
yRange: true,
color: true,
onClick: false,
};
function shouldUpdate(
oldProps: ScatterProps,
newProps: ScatterProps
) {
let k: keyof ScatterProps;
for(k in oldProps) {
if(oldProps[k] !== newProps[k] && REQUIRES_UPDATE[k]) return true;
return false;
}
}
타입스크립트의 많은 타입 구문은 사실 불필요하다. 코드의 모든 변수에 타입을 선언하는 것은 비생산적이며 형편없는 스타일이다.
객체 리터럴에 타입을 명시하면 잉여 속성 체크에 의해서 타입 오타같은 오류를 잡을 수 있다. 그리고 변수가 사용되는 순간이 아니라 할당하는 시점에서 오류를 표시해준다.
만약 타입 구문을 제거하면 잉여 속성 체크가 동작하지 않고, 객체가 사용되는 곳에서 타입 오류가 발생한다.
타입 추론이 가능할지라도 구현상의 오류가 함수를 호출한 곳까지 영향을 미칠 수 있기 때문에 타입 구문을 명시하는 것이 좋다.
반환 타입을 명시하면 함수에 대해 더욱 명확하게 알 수 있다.
반환값에 명명된 타입을 사용할 수 있다. (number 처럼 두루뭉실한 타입이 아니라 구체적인 타입을 명시할 수 있음)
반환 타입에 대한 주석을 작성할 수 있어서 더욱 자세한 설명이 가능하다.
eslint 규칙중
no-inferrable-types를 사용해 작성된 모든 타입 구문이 정말 필요한 것인지 확인할 수 있다.
변수의 범위 내에서 값이 변경될 때 타입 시스템의 유연성에 관련된 것이라고 볼 수 있다.

getComponent 함수는 두 번째 매개 변수에 "x" | "y" | "Z" 타입을 기대했지만, x 타입은 할당 시점에 넓히기가 동작해서 string으로 추론 되었다. string 타입은 "x"|"y"|"z" 타입에 할당이 불가능하므로 오류가 된 것이다.
const v: { x: 1|3|5; } = {
x: 1,
};
→ 함수의 매개변수로 값을 전달하는 경우
변수 선언이 아니라 const 단언이다.
const 단언문은 온전히 타입 공간의 기법이다.
타입스크립트가 넓은 타입으로부터 좁은 타입으로 진행하는 과정으로 조건문을 통해서 타입을 좁혀나갈수 있다.
타입스크립트는 일반적으로 조건문에서 타입을 좁히는데 매우 능숙하다.