TIL/TypeScript

[TypeScript] 이펙티브 타입스크립트 item 21~23

JoJobum 2022. 7. 28.

item21

상수를 사용해서 변수를 초기화할 때 타입을 명시하지 않으면 타입체커는 타입을 유추하여 결정

즉 지정된 단일 값을 가지고 할당 가능한 값들의 집합을 유추함, 이를 타입 넓히기라고 함

const mixed = ['x', 1];
//후보: ('x' | 1)[]
// ['x', 1]
// [string, number]
// readonly [string, number]
// (string|number)[]
// readonly (string|number)[]
// [any, any]
// any

정보가 충분하지 않으면 어떤 타입으로 추론되어야 하는지 모름

 

이러한 넓히기를 제어할 수 있는 것이 

 

const : 재할당을 막기에 타입스크립트가 더 좁은 타입으로 추론할 수 있다

interface Vector3D { x:number; y: number; z:number; } 
function getComponent(vector: Vector3D, axis: 'x'|'y'|'z'){
	return vector[axis];
}

let x = 'x'; // <-- x는 타입 넓히기를 통해 string으로 추론됨 
let vec = {x: 10, y:20, z:30};
getComponent(vec, x); // <-- string 타입은 "x"|"y"|"z" 타입에 할당 불가능 => 오류

const x = 'x'; // <-- const를 활용해 타입 좁혀 "x" 타입으로 추론함 
let vec = {x: 10, y:20, z:30};
getComponent(vec, x); // <-- "x" 타입은 "x"|"y"|"z" 타입에 할당 가능 => 통과

But 만능X, 객체나 배열에서 문제 존재 

왜냐 타입스크립트는 오류를 잡기 위해 구체적으로 타입을 추론하려하지만, 잘못된 추론을 할 정도까지는 구체적으로 추론하지 않기에 이러한 문제들이 발생

 

타입 추론의 강도를 직접 제어하려면

  • 명시적 타입 구문을 제공
const test: { x: 1|3 } = {
	x: 1,
} // 타입이 { x: 1|3; }
  • 타입 체커에 추가적인 문맥 제공 Ex)함수의 매개변수로 값을 전달
  • const 단언문을 사용하는 것, 값 뒤에 as const를 작성하면 최대한 좁은 타입으로 추론함

 

item22

타입 좁히기 

const test = document.getElementById('foo');
if(test){
	~~~ // 타입이 HTMLElement
}else{
	~~~ // 타입이 null
}

if(test instance of HTMLElement){
	~~~ // 타입이 HTMLElement
}else{
	~~~ // 타입이 null
}

조건문으로 타입 좁히기

이외에도 태그된/구별된 유니온과 사용자 정의 타입 가드를 사용하여 타입 좁히기 과정을 만들 수 있음

 

item23

변수의 값은 변경될 수 있지만 타입은 일반적으로 변경X => 객체를 생성할 때는 속성을 하나씩 추가하는 것이 아닌, 한번에 생성해야 타입 추론에 유리함 

객체를 나눠서 만들어야 한다면, 타입 단언문(as)를 사용해 타입 체커를 통과하게 한다

 

const point = { x: 3, y: 4};
const id = { name: 'test' };

const namePoint = {};
Object.assign(namePoint, point, id); 

// 객체 전개 연산자... 를 활용하여 객체 한번에 만들자
const namePoint2 = { ...point, ...id }; 

/* namePoint, namePoint2 결과
[LOG]: {
  "x": 3,
  "y": 4,
  "name": "test"
} 
*/

 

타입에 조건부 속성을 추가하려면 속성을 추가하지 않은 null 또는 {}으로 객체 전개를 사용하면 된다

declare let hasValue: boolean;
const label = = { name: 'trash' };
const a = { ...label, ...(hasValue ? {value: 100} : {})};

/* 추론된 a의 타입
const a: {
    value?: number | undefined;
    name: string;
}
*/
반응형

댓글