Typescript : 복습정리 - 1 (타입스크립트의 설치, any와 unknown의 차이, Narrowing, Literal Type, Union Type..)
자바스크립트는 동적언어이다. 자유도가 높은 언어이며 타입이 렌더링 되면서 정해진다.
이러한 점은 규모가 큰 프로젝트가 될 수록 단점으로 작용한다. 유지보수에 어려움을 겪는다.
타입을 엄격하게 동적->정적으로 관리하기 위해 타입스크립트를 사용한다.
타입스크립트에서는 타입이 잘못되었을 경우 그 부분이 잘못되었다고 구체적으로 알려주고, 오타교정도 가능하다.
리액트 + 타입스크립트의 설치
1) 기존의 React프로젝트에 타입스크립트 설치하기.
작업폴더경로에서 터미널을 오픈한 뒤,
npm install --save typescript @types/node @types/react @types/react-dom @types/jest
or
yarn add --save typescript @types/node @types/react @types/react-dom @types/jest
그 다음 .js파일들을 .ts로 바꿔서 이용할 수 있다.
2) 새로 리액트 작업폴더를 만들고 진행할 때
npx create-react-app my-app --template typescript
- 기본 사용
let name : string = “강철”
변수뒤에 : type 을 붙임으로써 타입을 사전에 결정할 수 있다.
타입에 들어올 수 있는 것으로는 string, number, boolean, bigint, null, undefined,[], {} 가 있다.
하지만 모든 변수에 일일이 타입지정을 해줄 필요는 없다.
변수생성시 타입스크립트에서 타입을 자동으로 부여해 주기 때문이다. 간단한 변수들은 타입을 생략해도 괜찮다.
- any와 unknown 의 차이.
두 타입 모두 타입스크립트를 사용하는 의미가 없어지기 때문에 사용하지 않는게 좋지만
그나마 unknown이 나은 이유는 any는 타입자체가 사라지게 하기 때문이다.
let name : unknown;
name = {};
let user :string = name;
위의 경우 에러가 난다. name의 타입은 Unknown이었지만, {}를 할당함으로서
object로 타입이 지정되었기 때문이다.
재할당 할 경우 할당된 데이터의 타입으로 타입지정이 된다.
반면에 any를 사용했을 경우
let name : any;
name = {};
let user:string = name;
에러가 나지 않는다. 타입 자체를 해제 시켜버리기 때문이다.
또한 수학연산의 경우에도 unknown의 경우 연산이 불가능해 타입 에러를 띄워주는 반면
any의 경우 연산까지 가능하기 때문에 타입지정의 의미가 전혀 없다고 볼 수 있다.
let name : unknown;
name -10 // error
let name : any;
name -10 // no error
Union type 사용시 주의사항.
+ 수학연산
let age : string;
age + 1 //no error
let age : number;
age + 1 // no error
let age : string | number;
age + 1 // error !!
string | number 는 곧 새로운 타입인 것. string도 아니고 number도 아니게 되는 것이다.
함수에서의 type 사용
function counter(x) {
return x+1
}
// 타입지정
function counter(x:number) : number {
return x+1
}
파라미터에 대한 타입과 리턴값에 대한 타입 두가지를 지정해준다.
리턴값이 없는 함수도 있다. 이 경우는 void. 아무것도 리턴하지 말아주세요. 리턴값이 생기면 에러를 내주세요. 라는 의미이다.
function counter(x:number) : void {
1+1
}
추가로 함수 타입지정시 자바스크립트와의 차이점은,
파라미터에 타입을 지정해 주었다면 함수 호출시 무조건 인자를 넣어주어야 한다는 것이다.
자바스크립트에서는 파라미터값이 있어도 인자 생략이 가능하다.
counter() -> error
파라미터가 없어도 되는 경우를 만들고 싶다면 파라미터값 뒤에 물음표를 쳐주면 된다.
function counter(x?:number) : void {
1+1
}
오브젝트값에도 적용가능하다 키 값 뒤에 물음표를 쳐주면 그 값은 없어도 된다.
물음표를 쳐주는건 사실 undefined가 포함된 유니온 타입과 같은 의미이다.
function counter(x:number | undefined) : void {
1+1
}
//같은 의미
function counter(x?:number) : void {
1+1
}
Narrowing
function counter ( x : number | string ) : void {
console.log(x+3)
}
counter(2) -> error
왜냐하면 number|string이라는 타입은 연산이 불가하기 때문이다. 명확하게 number타입이어야 한다 !
narrowing 을 통해 해결 가능하다.
union 타입 등으로 인하여 어떤 변수의 타입이 불확실 할 때, if 문 등으로 narrowing 해주어야 조작이 가능하다.
function counter( x : string | number ) {
if (typeof x === “string”) {
return x +”1”
} else { return x + 1}
}
in 키워드로 object narrowing 하기
type Fish = {swim : string}
type Bird = {fly : string}
function test(animal : Fish | Bird) {
animal.swim //안된다. Union 타입을 사용하는 경우는 꼭 narrowing에 대하여 생각해 보아야 한다.
}
function test(animal : Fish | Bird) {
if (typeof animal === Fish) { // 안된다. typeof는 string, number와 같은 기본 타입에만 가능.
}
}
이 때. in을 쓸 수 있다. 키 값으로 검색하네.
type Fish = {swim : string}
type Bird = {fly : string}
function test(animal : Fish | Bird) {
if ( ’swim’ in animal ) {
animal.swim // 가능!
}
}
타입을 변수로 지정하기. type alias
대문자시작 작명
AnimalType 이렇게 붙여도 좋음 . 재할당은 불가하다 !
type Animal = string | number | undefined;
let 동물 : Animal;
오브젝트 타입에서 유용하다.
type Animal = { name : string, age : number }
let 동물 : Animal = {name : “kim”, age : 20}
오브젝트 안의 값을 바꾸지 못하게 하고 싶을 때 readOnly
type AnimalType = {
readOnly name : string,
readOnly age : 20,
}
타입 합치기도 가능
type Name = string;
type Age = number;
type Person = Name | Age
or
type PositionX = { x : number};
type PositionY = { y : number};
type Coordinate = PositionX & PositionY
Literal Types로 만드는 const 변수.
let 이름 : “kim”; <— 이름이라는 변수에는 kim이라는 문자만 들어올 수 있다.
변수에 뭐가 들어올지 더 엄격하게 관리가능하고, 자동완성이 가능하다.
function test( a : ‘hello’ | “hi” ) : 1 | 0 {
}
test라는 함수 인자로는 hello 혹은 hi 밖에 못오고,
return 값으로는 1 또는 0 밖에 못오게 된다.
const 변수의 경우 오브젝트 형식일 경우 한계를 가진다. 재할당만 못하게 하기 때문이다.
오브젝트 안의 값을 변경할 수 있다. 하나의 데이터만 저장할 수 있다.
하지만 Literal type을 쓰면 여러가지 선택지 데이터를 엄격하게 관리할 수 있고, 오브젝트 형식또한 엄격하게 관리 가능하다.
literal type의 문제점.
const file = {
name: "kim",
};
function tester(a: "kim") {}
tester("kim");
tester(file.name); //error!
아래의 경우 에러가 난다.
a : “kim” 이라는 것은 킴이라는 타입만 들어올 수 있다는 것이지, 다른 타입들이 들어올 수 있다는 의미가 아니기 때문이다.
***질문 - 결국 “kim”의 타입도 string이잖아..?
자료값이 아니라 타입을 지정해준다는 것을 잊지 말아야 한다.
As const 사용.
const file = {
name: "kim",
} as const;
function tester(a: "kim") {}
tester(file.name);
이렇게 as const 를 붙이면 에러가 안난다.
이 변수를 만들 때 타입지정을 literal 타입처럼 해달라. 라는 의미이다. name의 타입을 “kim”으로 지정해준다.
키 값의 타입을 오른쪽의 벨류로 지정해주고, object 속성들에 모두 readonly를 붙여 준다.
참고사이트
코딩애플 타입스크립트 강의 : https://codingapple.com/