본문 바로가기
Typescript

type alias & readonly & type alias extends, literal type과 as const

by 루에 2022. 1. 1.
반응형

타입을 다 기재할 필요 없이 변수에 담아 사용 가능하다.

// 아래 변수의 타입을
let value: string = "lee";

// alias해서 사용
type Name = string;
let newValue: Name = "lee";

 

const 변수는 값을 바꿀 수 없지만, object의 내용은 바꿀 수 있다.

그래서 그 값을 변경하지 못하도록 readonly로 만들 수 있다.

const name = "lee";
name = "kim";	// 에러

const value = { name : "lee", age : 25 };
value.name = "kim";	// 에러 안남

type Person = {
	readonly name : string,
	age : number
}
const newValue : Person = { name : "lee", age : 25 };
newValue.name = "kim";	// 에러
newValue.age = 33;		// 에러 안남

 

object는 & 키워드로 type을 합칠 수 있다.

하지만 같은 이름의 속성을 합칠 경우, 오른쪽에 있는 오브젝트의 타입으로 지정되거나 never 변수가 된다.(never는 나중에..)

type a = {a: number};
type b = {a: string};
type c = a & b;	// never

let temp3: c = {a:"1"};	// 에러 

// 정상적으로 쓴다면
type a = {a: number};
type b = {b: string};
type c = a & b;

let temp3: c = { a : 1, b : "문자열" };

 

변수를 primitive type이 아니라 좀 더 명확하게 지정할 수 있고, literal type이라 부른다.

// "바나나" | "딸기" | "사과" 세 개 중에 하나만 들어갈 수 있다.
type Literal = "바나나" | "딸기" | "사과"
let value1 = "멜론";	// 에러
let value2 = "바나나";	// 에러 안남

// 함수도 가능
function func(param: "바나나" | "딸기" | "사과"): 1 | 0 {
	if(typeof param === "Literal") {
    	return 1;
    } else {
    	return 0;
    }
}

이를 통해 에러를 좀 더 방지할 수 있으며, 스니펫이 지원되어 값 넣기가 편해지기도 한다.

 

literal type에서 object를 사용할 때는 애매한 상황이 발생하기도 하는데 아래와 같은 문제가 있다.

let value = {
    name : "lee",
    age : number
}

function func(param : "lee"): void {
	console.log(param);
}
console.log(value.name)	// "lee"

// 위처럼 콘솔을 찍으면 "lee"가 출력된다.
// func함수의 param의 타입도 "lee"이다.
// 이론상으로는 func(Person.name) 을 호출할 경우 정상적으로 호출되어야 한다.


func(Person.name)	// 에러


에러가 발생하는 이유는, param은 "lee"라는 타입이지만 Person.name은 "lee" 라는 문자열이기 때문이다.

즉, param : "lee" 의 의미는 "lee"라는 값을 넣을 수 있다가 아니라 "lee"라는 타입을 넣을 수 있다는 의미이다.

사견으로는 말장난처럼 생각되긴 하는데, 아마도 js에 타입 개념을 넣다보니 구멍이 생길 수 밖에 없지 않을까 싶다.

어쨋든, 이러한 문제를 해결하는 방법은 두가지가 있는데

1. 변수에 타입을 명확하게 지정한다.

1-1. assertion의 as 로 타입을 속인다.

2. as const 키워드를 이용해 const화 시킨다.

// 1. 타입을 명확히
let value : { name : "lee", age : number } = {
    name : "lee",
    age : 14
}

function func(param : "lee"): void {
	console.log(param);
}
func(value.name)

// 혹은 assertion의 as로 사용
func(value.name as "lee");

 

2. as const를 사용하면 아래처럼 변수의 선언문이 내부적으로 변경되어 정상적으로 사용할 수 있다.

as const를 붙이기 전에는 name의 타입은 string이 었지만,

as const를 붙임으로 인해 readonly 속성이 붙고 name의 value였던 "lee" 가 타입이 된다.

 

as-is
to-be

 

literal type을 함수에도 사용가능하지만 return 값은 엄격하게 보고 parameter는 그렇지 못한 부분이 있다.

아래의 temp5~7모두 정상적으로 실행이 가능한데, js로 변환된걸 보면 왜 정상인지 알 수가 있다.

하지만 그럼에도 temp5~7의 값에 들어있는 함수에 a라는 parameter가 없는데도 에러 체크 하지 않는 부분은 좀 아쉽다.

type FuncType = (a: string) => number;

let temp5 : FuncType = () => {
    console.log("temp5");
    return 10;
};
let temp6 : FuncType = function () {
    console.log("temp6");
    return 10;
}
let temp7 : FuncType = function func5() {
    console.log("temp7");
    return 10;
}
temp5("lee");
temp6("lee");
temp7("lee");

위 ts 파일이 js로 컴파일 되면

let temp5 = () => {
    console.log("temp5");
    return 10;
};
let temp6 = function () {
    console.log("temp6");
    return 10;
};
let temp7 = function func5() {
    console.log("temp7");
    return 10;
};
temp5("lee");
temp6("lee");
temp7("lee");
반응형

댓글