function arraySum(arr: readonly number[]) {
let sum = 0, num;
whjile((num = arr.pop()) !== undefined) {
// ❌ 'readonly number[]'형식에 'pop' 속성이 없습니다.
sum += num;
}
return sum;
}
✔ readonly number[]과 number[]의 차이점
❗ 변경 가능한 배열을 readonly 배열에 할당할 수는 있지만 반대는 불가능하다.
// 위의 arraySum 고치기
function arraySum(arr: readonly number[]) {
let sum = 0;
for (const num of arr) {
sum += num;
}
return sum;
}
만약 함수가 매개변수를 변경하지 않는다면, readonly로 선언하자. 어떤 함수를 readonly로 만들면, 그 함수를 호출하는 다른 함수도 모두 readonly로 만들어야 한다.
인덱스 시그니처에도 readonly를 사용하면 객체의 속성이 변경되는 것을 방지할 수 있다.
interface Array<T> {
// ...
[n: number]: T;
}
const xs = [1, 2, 3];
const x1 = xs["1"]; // ❌ 에러 (인덱스 식이 number형식이여야 함)
👍 타입 체크 시점에 오류를 잡을 수 있어서 유용함
배열 순회 방법
❗ 타입이 불확실하다면 for-in 루프는 for-of 또는 C스타일 for 루프에 비해 몇 배나 느림
어떤 길이를 가지는 배열과 비슷한 형태의 튜플을 사용하고 싶다면 타입스크립트에 있는 ArrayLike 타입을 사용한다.
const REQUIRES_UPDATE: { [k in keyof ScatterProps]: boolean } = {
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;
}
[k in keyof ScatterProps]는 타입체커에게 REQUIRES_UDPATE가 ScatterProps와 동일한 속성을 가져야 한다는 정보를 제공한다.
매핑된 타입은 한 객체가 또 다른 객체와 정확히 같은 속성을 가지게 할 때 이상적이다
타입 추론이 된다면 명시적 타입 구문을 필요하지 않다
Product 타입과 기록을 위한 함수
interface Product {
id: number;
name: string;
}
function logProduct(product: Product) {
const id: number = product.id;
const name: string = product.name;
}
후에 id에 문자도 들어 있을 수 있음을 알게 되었을 때 Product내의 id 타입을 변경하면 logProduct 내의 id 변수 선언에서 에러가 발생한다.
👉 비구조화 할당문을 사용하여 구현하는 것이 낫다
function logProduct(product: Product) {
const { id, name } = product;
}
비구조화 할당문은 모든 지역변수의 타입이 추론되도록 한다.
이상적인 타입스크립트 코드는 함수/메서드 시그니처에 타입 구문을 포함하지만, 함수 내에서 생성된 지역 변수에는 타입 구문을 넣지 않는다
✔ 타입이 추론될 수 있음에도 여전히 타입을 명시하고 싶은 경우
변수의 값은 바뀔 수 있지만 그 타입은 보통 바뀌지 않는다
✔ 다른 타입에는 별도의 변수를 사용하는게 바람직한 이유