2022. 12. 28. 18:09ㆍTypeScript
⚡️변수를 만들 때 타입지정
1. 변수명 : 타입명 이렇게 씁니다.
2. 타입으로 쓸 수 있는 것들은 string, number, boolean, bigint, null, undefined,[], {} 등이 있습니다.
(타입지정은 대문자 String 아닙니다 소문자 string임)
let 이름 :string = 'kim'
let 나이 :number = 35
let 결혼 :boolean = true
let 이름 :string[] = ['kim', 'park']
let 나이 :{ age : number } = { age : 35 }
let 일정 :(string | number)[] = ['어제', 28]
⚡️타입을 변수에 담아서 사용 Type Aliases (별칭)
type Animal = string | number | undefined;
let 동물 :Animal;
1. 변수만드는 것 처럼 type 이라는 키워드를 쓰는걸 type alias 라고 합니다.
2. type 타입변수명 = 타입종류
3. 타입을 변수처럼 만들어서 쓰는 alias 문법입니다. 관습적으로 대문자로 시작합니다.
⚡️object에 타입지정할 때 자주 활용
type MyObject = {
name? : string,
age : number
}
let 철수 :MyObject = {
name : 'kim',
age : 50
}
1. object 타입도 정의가 너무 길면 type 키워드로 변수에 담아 사용가능합니다.
2. type 키워드 대신 비교적 최근에 나온 interface 키워드를 이용해도 무방합니다.
3. 특정 속성이 선택사항이면 물음표를 기입가능합니다.
⚡️object에 key을 전부 타입 지정
type MyObject = {
[key :string] : number,
}
let 철수 :MyObject = {
age : 50,
weight : 100,
}
1. object안에 어떤 속성이 들어갈지 아직 모른다면
2. 그냥 전부 싸잡아서 타입지정도 가능합니다.
3. index signature라고 합니다.
⚡️Object에 쓸 수 있는 interface 문법
interface 문법을 쓰시면 object 자료형의 타입을 보다 편리하게 지정가능합니다.
interface Square {
color :string,
width :number;
}
let 네모 :Square = { color : 'red', width : 100 }
1. interface는 object랑 비슷한 모습으로 작성하면 됩니다.
2. type alias와 용도와 기능이 똑같습니다.
3. ⓵대문자로 작명하고 ⓶{ } 안에 타입을 명시해주면 됩니다.
(참고) 한 줄 끝나면 콤마대신 세미콜론도 가능합니다.
⚡️interface 장점은 extends도 가능
interface Student {
name :string,
}
interface Teacher {
name :string,
age :number,
}
1. 위의 식을 extends 문법쓰시면 줄일 수 있습니다.
2. extends 문법은 interface 여기에 복사해달라는 뜻입니다.
interface Student {
name :string,
}
interface Teacher extends Student {
age :number
}
1. Student interface를 extends 해달라고 적으면 Student 안에 있던걸 복사해서 Teacher에 넣어줍니다.
2. 이제 Teacher 타입은 age, name 속성을 가지고 있습니다.
⚡️type 키워드와의 차이점
type alias와 interface는 거의 똑같은 기능을 제공합니다.
그래서 차이점은 extends 문법이 약간 다르다는 점이다
interface Animal {
name :string
}
interface Cat extends Animal {
legs :number
}
interface의 경우 일반적으로 이렇게 extends 합니다.
type Animal = {
name :string
}
type Cat = Animal & { legs: number }
1. type alias의 경우 extends는 안되고 & 기호를 쓰면 object 두개를 합칠 수 있습니다.
2. 이러면 Cat 타입은 name, legs 속성을 가질 수 있습니다.
interface Student {
name :string,
}
interface Teacher {
age :number
}
let 변수 :Student & Teacher = { name : 'kim', age : 90 }
1. interface도 type처럼 & 기호를 이용해도 복사가능
2. & 기호 쓰는걸 intersection이라고 부르는데 extends 와 유사하게 사용가능합니다.
(주의) extends 쓸 때 타입끼리 중복속성이 발견될 경우 에러로 혼내주는데 & 쓰면 때에 따라 아닐 수도 있습니다.
⚡️타입이름 중복선언시
interface Animal {
name :string
}
interface Animal {
legs :number
}
1. interface의 경우 타입이름 중복선언을 허용해주며 중복시 extends 한 것이랑 동일하게 동작합니다.
2. 이러면 Animal 타입은 name, legs 속성을 가질 수 있습니다.
(장점) type 선언을 자주 쓰는 외부 라이브러리 이용시 type 선언을 내가 덮어쓰기, override 하기 편리합니다.
type Animal = {
name :string
}
type Animal = {
legs :number
}
type의 경우 중복선언을 허용하지 않습니다. 에러발생
(참고) 일반적인 상황에선 type 키워드 자주 활용하면 되는데
다른 사람이 내 코드를 이용하는 상황이 많으면 interface로 유연하게 만드는게 좋습니다.
그래서 타입스크립트로 작성된 라이브러리들은 interface로 타입정해놓은 곳이 많습니다.
혹은 object 자료형은 전부 interface로 만들고 다른 자료형은 type 키워드로 만들고 이런 것들도 괜찮습니다.
type과 interface 문법을 잘 알고 있으면 기준은 정하기 나름입니다.
⚡️extend 할 때 object 안의 속성이 중복될 경우
interface Animal {
name :string
}
interface Dog extends Animal {
name :number
}
Animal을 복사해서 Dog interface를 만들어봤습니다.
근데 name 속성이 중복되네요? 그럼 에러납니다.
interface Animal {
name :string
}
interface Dog {
name :number
}
let 변수 :Dog & Animal = { name : '멍멍' }
1. & 연산자로 Dog, Animal을 extend하면 name 속성이 중복되어 에러 발생
2. interface 말고도 type 키워드도 똑같은 현상이 일어납니다.
(주의) 근데 name : string , name : number 라서 에러가 나는 것이지
둘다 name : string 타입이면 에러가 나지 않습니다. 하나로 합쳐줌
⚡️array에 타입 지정 할 때 자주 활용
type Member = [number, boolean];
let john:Member = [100, false]
1. array 자료 안에 순서를 포함해서 어떤 자료가 들어올지 정확히 지정하고 싶으면 tuple 타입을 쓰면 됩니다.
2. 대괄호 [ ] 안에 들어올 자료의 타입을 차례로 적어주면 됩니다.
배열: 여러 개의 데이터들을 모은 집합. 추가와 삭제가 가능하다. [ ]로 사용한다.
튜플: 리스트와 동일하게 여러 객체를 모아서 담는다. 숫자, 문자, 객체, 배열, 튜플 안의 튜플 전부 가능하다. 하지만 튜플 내의 값은 수정이 불가하다. 추가도, 삭제도 안 된다. 한번 만들어지면 끝까지 가지고 가야 된다. ( )로 사용하고, ( )가 없어도 동일하게 사용 가능하다.
⚡️type 속성 몇개가 선택사항 일때
object자료는 color, width 속성이 둘다 필요하지만 어떤 object 자료는 color 속성이 선택사항이라면
type alias를 여러개 만들어야하는게 아니라 물음표연산자만 추가하면 됩니다.
type Square = {
color? : string,
width : number,
}
let 네모2 :Square = {
width : 100
}
1. Square라는 type alias를 적용한 object 자료를 하나 만들었습니다.
2. 근데 color 속성이 없어도 에러가 나지 않습니다.
3. 물음표는 "undefined 라는 타입도 가질 수 있다~"라는 뜻임.
⚡️type 키워드 여러개를 합치는 방법
type Name = string;
type Age = number;
type NewOne = Name | Age;
1. OR 연산자를 이용해서 Union type을 만들 수도 있습니다.
2. 위 코드에서 NewOne 타입에 마우스 올려보시면 string | number라고 나올겁니다.
type PositionX = { x: number };
type PositionY = { y: number };
type XandY = PositionX & PositionY
let 좌표 :XandY = { x : 1, y : 2 }
1. object에 지정한 타입의 경우 합치기도 가능합니다.
2. & 기호를 쓴다면 object 안의 두개의 속성을 extend해줍니다.
3. 위 코드에서 XandY 타입은 { x : number, y : number } 이렇게 정의되어있을 겁니다.
물론 Type alias & Type alias 만 가능한게 아니라
Type alias & { name : string } 이런 것도 가능합니다.
⚡️type 키워드는 재정의가 불가능
type Name = string;
type Name = number;
이러면 에러가 날 겁니다.
interface 키워드를 사용하면 재정의가 가능합니다. 재정의하면 & 하는거랑 똑같은 기능을 하는데
하지만 재정의 불가능한 편이 더 안전합니다.
⚡️readonly로 잠그기
const 출생지역 = 'seoul';
출생지역 = 'busan'; //const 변수는 여기서 에러남
const 변수는 값이 변하지 않는 변수를 만들고 싶을 때 const 씁니다.
재할당시 에러가 발생합니다.
const 여친 = {
name : '엠버'
}
여친.name = '유라'; //const 변수지만 에러안남
하지만 object 자료를 const에 집어넣어도 object 내부는 마음대로 변경가능합니다.
const 변수는 재할당만 막아줄 뿐이지 그 안에 있는 object 속성 바꾸는 것 까지 관여하지 않기 때문입니다.
object 속성을 바뀌지 않게 막고 싶으면 타입스크립트 문법을 쓰십시오.
readonly 키워드는 속성 왼쪽에 붙일 수 있이면 특정 속성을 변경불가능하게 잠궈줍니다.
type Girlfriend = {
readonly name : string,
}
let 여친 :Girlfriend = {
name : '엠버'
}
여친.name = '유라' //readonly라서 에러남
한번 부여된 후엔 앞으로 바뀌면 안될 속성들을 readonly로 잠궈봅시다.
(물론 readonly는 컴파일시 에러를 내는 것일 뿐 변환된 js 파일 보시면 잘 바뀌긴 합니다)
⚡️literal type
type NameType = 'kim' | 'park;
let 이름 :NameType = 'kim';
string number 이런 것 뿐만 아니라 나만의 타입을 만들어 사용가능합니다.
저렇게 원하는 글자나 숫자를 입력하면 이름이라는 변수엔 앞으로 'kim' 또는 'park'만 들어올 수 있습니다.
특정 글자나 숫자만 가질 수 있게 제한을 두는 타입을 literal type 이라고 부릅니다.
let 방향: 'left' | 'right';
방향 = 'left';
or 기호 써도 됩니다. 이제 'left' 또는 'right' 글자만 가질 수 있는 변수가 완성되었군요.
function 함수(a : 'hello') : 1 | 0 | -1 {
return 1
}
함수도 똑같습니다.
파라미터 타입선언할 때 글자나 숫자를 집어넣으시면 그 만 파라미터로 넣을 수 있고
return 타입선언할 때도 글자나 숫자를 집어넣으시면 그 값만 return할 수 있습니다.
⚡️as const 문법
const 변수는 값을 바꿀 수 없는 변수입니다.
const 변하면안되는변수 = 123;
1. 변하지않는 정보를 저장하고 싶을 때 const를 사용
2. 가끔은 변하는 중요한 정보를 저장하고 싶을 땐 const가 무쓸모입니다.
const 이름 = 'kim' | 'park' (이런 식의 문법은 자바스크립트에 없음)
타입스크립트를 설치하고 literal type 쓰면 변수가 'kim' 또는 'park' 만 가질 수 있는 식을 만들수 있습니다.
Q. 왜 에러가 나겠습니까?
var 자료 = {
name : 'kim'
}
function 내함수(a : 'kim') {
}
내함수(자료.name)
함수는 'kim' 타입만 입력할 수 있다고 해놨고
자료.name 이라는건 string 타입이지 'kim' 타입이 아니기 때문입니다.
⭐️ 이런걸 해결하고 싶으면 ⭐️
1. object 만들 때 타입을 잘 미리 정하든가
2. 예전에 배웠던 assertion을 쓰시든가 (as 'kim' 이런걸 붙이는 겁니다)
3. 아니면 as const 라는걸 애초에 object 자료에 붙일 수 있습니다.
var 자료 = {
name : 'kim'
} as const;
function 내함수(a : 'kim') {
}
내함수(자료.name)
as const는 효과가 2개인데
1. 타입을 object의 value로 바꿔줍니다. (타입을 'kim'으로 바꿔줍니다)
2. object안에 있는 모든 속성을 readonly로 바꿔줍니다 (변경하면 에러나게)
object를 잠그고 싶으면 as const를 활용해보도록 합시다.
⚡️Union type 사용
"이 변수엔 string 또는 number가 들어올 수 있습니다~" 라고 타입정의를 하고싶으면 | 연산자를 씁시다.
OR 연산자 같은 느낌인데 이런 타입을 전문용어로 Union type 이라고 부릅니다.
let 이름: string | number = 'kim';
let 나이: (string | number) = 100;
괄호쳐도 안쳐도 됩니다.
이러면 name, age 변수엔 string 또는 number만 들어올 수 있습니다.
그리고 할당하는 순간 타입은 string 또는 number 중 하나로 변합니다.
var 어레이: (number | string)[] = [1,'2',3]
var 오브젝트: {data : (number | string) } = { data : '123' }
특징은 변수에 정의된 Union 타입은 할당과 동시에 OR 역할이 사라집니다.
array, object에 정의된 Union 타입은 OR 연산자가 유지됩니다.
type nameType = string | number;
let 이름 :nameType = 'kim';
Q. 이 코드는 왜 에러가 나는 것이죠?
let 나이: string|number;
나이 + 1;
let 나이: unknown = 1;
나이 + 1;
unknown은 number타입이 아닙니다.
string|number도 number 타입이 아닙니다. (union type은 새로운 타입을 하나 만든 겁니다)
내가 조작할 변수의 타입이 무엇인지 확실하게 체크하는 narrowing 또는 assertion 스킬을 사용해야합니다.
⚡️any 타입
아무 자료나 집어넣을 수 있는 타입입니다.
쉽게 비유하면 실드해제입니다.
let 이름: any = 'kim';
이름 = 123;
이름 = undefined;
이름 = [];
any 타입은 실드 해제 문법이기 때문에 갑자기 타입을 마구 바꿔도 에러가 나지 않는다
any 타입은 좋다고 막쓰면 안되는 이유 : 버그가 생길 경우 왜 그런지 추적하기가 어렵다.
그래서 비상시 쓰는 변수 타입체크 해제기능 이런 용도로 씁시다.
⚡️unknown 타입
요즘 타입스크립트는 unknown 타입을 사용합니다.
any와 똑같이 모든 타입을 집어넣을 수 있습니다.
let 이름: unknown = 'kim';
이름 = 123;
이름 = undefined;
이름 = [];
이래도 에러가 나지 않습니다.
아직 어떤 타입이 들어올지 모를 경우, 다양한 타입을 집어넣어야할 경우 이걸 사용해보시길 바랍니다.
중요한 특징은
1. unknown 타입엔 모든 자료 다 집어넣을 수 있음
2. 자료집어넣어도 타입은 그대로 unknown입니다.
let 이름: unknown;
let 변수1: string = 이름;
let 변수2: boolean = 이름;
let 변수3: number = 이름;
let 이름: unknown;
이름[0];
이름 - 1;
이름.data;
unknown 타입을 다른 곳에 집어넣으려고 하면그쪽 실드가 발동해서 에러가 납니다.
(any는 안그럼)
<결론>
결론은 아직 뭘 집어넣을지 모르겠는데 약간의 안정성을 도모하고 싶으면 unknown 타입을 써봅시다.
근데 실은 코드짜다가 any, unknown 부여할 경우는 별로 없습니다.
⚡️함수에 타입지정하려면 2곳 가능
함수는 총 두 군데 타입지정이 가능합니다.
1. 함수로 들어오는 자료 (파라미터)
2. 함수에서 나가는 자료 (return)
function 내함수(x :number) :number {
return x * 2
}
1. 함수로 들어오는 파라미터 타입지정은 파라미터 옆에 적으면 됩니다.
2. 함수가 실행된 후 남는 값 (return 우측에 있는 값) 타입지정하고 싶으면 함수명() 우측에 적으면 됩니다.
⚡️함수는 void 타입
함수는 특이하게도 void라는 타입을 사용가능합니다.
'아무것도 없이 공허함'을 뜻하는 타입인데 return할 자료가 없는 함수의 타입으로 사용가능합니다.
function 내함수(x :number) :void {
return x * 2 //여기서 에러남
}
그럼 이제 이 함수에서 뭔가를 return하려고할 때 에러를 냅니다.
함수에 return 방지장치를 주고 싶을 때 void 타입을 활용하시면 되겠습니다.
⚡️파라미터가 옵션일 경우
함수에 파라미터자리를 만들어놨지만 가끔 파라미터 없이 쓸 때도 있습니다.
그럴 경우 타입스크립트에선 미리 "이 파라미터는 옵션임" 이렇게 정의를 해주셔야 에러가 나지 않습니다.
function 내함수(x? :number) {
}
내함수(); //가능
내함수(2); //가능
파라미터 우측에 그냥 물음표치면 됩니다.
그럼 앞으로 내함수()를 사용할 때 파라미터 없이도 쓸 수 있습니다.
근데 물음표는 실은 x : number | undefined 이거랑 똑같은 의미입니다 (중요)
파라미터가 정의가 안되면 자동으로 undefined가 되니까 그걸 반영한거라고 볼 수도 있겠습니다.
⚡️함수도 타입을 변수에 담아서 사용 Type Aliases
함수 타입도 type alias로 저장해서 쓸 수 있습니다.
type NumOut = (x : number, y : number ) => number ;
자바스크립트로 함수만들 때 arrow function 이라고 부르는 => 문법을 써도 함수 만들어집니다.
(파라미터)=>{} //arrow function 문법
function(파라미터){} //일반 function 문법
arrow function의 장점은 기호 생략기능을 제공해준다는 점인데
1. arrow function에선 중괄호안에 return 어쩌구 코드밖에 없으면 중괄호 { } 생략해도 봐줍니다.
2. 파라미터가 한개 밖에 없으면 소괄호 ( ) 생략해도 봐줍니다.
type NumOut = (x : number, y : number ) => number
const ABC :NumOut = (x,y) => {
return x + y
}
함수를 만들 때 const 함수명 = function(){} 이렇게 해도 되니까
함수명 오른쪽에 함수명 : 타입별명 이렇게 지정해서 사용하는 것입니다.
⚡️methods 안에 타입지정하기
let 회원정보 = {
name : 'kim',
age : 30,
plusOne (x){
return x + 1
},
changeName : () => {
console.log('안녕')
}
}
회원정보.plusOne(1);
회원정보.changeName();
plusOne 그리고 changeName 함수를 object 자료에 집어넣었습니다.
arrow function, 일반함수 전부 object 안에 맘대로 집어넣을 수 있습니다.
Q. 위 코드에서 회원정보라는 변수에 타입지정 알아서 해보십시오.
- plusOne이라는 속성은 함수여야하고, 숫자를 넣어서 숫자를 뱉는 함수여야합니다.
- changeName이라는 속성은 함수여야하고, 아무것도 return하면 안됩니다.
type Member = {
name : string,
age : number,
plusOne : ( x :number ) => number,
changeName : () => void
}
⚡️타입 확정하기 Narrowing & Assertion
function 내함수(x :number | string){
return x + 1 //에러남
}
에러발생
Operator '+' cannot be applied to types 'string | number' and 'number'
string | number 같은 union type 에는 일반적으로 조작을 못하게 막아놔서 그렇습니다.
이런 메세지를 보면 ⓵타입을 하나로 Narrowing 해주거나 ⓶Assert 해주거나 둘 중 하나 해주면 됩니다.
⚡️Type Narrowing
if문 등으로 타입을 하나로 정해주는 것을 뜻합니다.
function 내함수(x :number | string){
if (typeof x === 'number') {
return x + 1
}
else if (typeof x === 'string') {
return x + 1
}
else {
return 0
}
}
1. if문과 typeof 키워드로 현재 파라미터의 타입을 검사
2. if문 쓸 때는 마지막에 else {} 이거 없으면 에러가 납니다.
3. return 하지않는 조건문이 있다면 나중에 버그가 생길 수 있어서 에러를 내주는 것인데
<해결방법>
tsconfig.js 파일에 "noImplicitReturns": false 추가하면 됩니다.
- 꼭 typeof를 쓸 필요는 없고 타입을 하나로 확정지을 수 있는 코드라면 어떤 것도 Narrowing 역할을 할 수 있습니다.
- in, instanceof 키워드도 사용가능합니다.
⚡️Type Assertion
타입을 간편하게 assert 할 수도 있습니다.
"이 변수의 타입을 number로 생각해주세요"
변수명 as string 이런 식으로 as라는 키워드 쓰면 됩니다.
function 내함수(x :number | string){
return (x as number) + 1
}
console.log( 내함수(123) ) //1231
변수명 as number 라고 쓰시면
"나는 이 변수를 number라고 주장하겠습니다~" 라는 뜻이며 실제로 그렇게 타입을 변경해줍니다.
as 키워드 사용시 특징
1. as 키워드는 union type 같은 복잡한 타입을 하나의 정확한 타입으로 줄이는 역할을 수행합니다.
( number 타입을 as string 이렇게 바꾸려고 하면 에러가 발생 )
2. as는 그냥 타입실드 임시 해제용입니다. 실제 코드 실행결과는 as 있을 때나 없을 때나 거의 동일합니다.
Q. 근데 내함수('123') 이렇게 숫자말고 문자를 입력하면 어떻게 됩니까
A. as number라고 썼긴 했지만 number 타입처럼 +1 해주진 않습니다. 콘솔창에 결과 출력해보면 '1231' 이렇게 출력될걸요
as는 그냥 주장만 하는거지 실제로 타입을 바꿔주는건 아니기 때문입니다.
<결론>
🔥 narrowing을 사용 🔥
as 키워드는 맘대로 타입을 개발자 맘대로 주장하는 역할이라 때문에 엄격한 타입체크기능을 잠깐 안쓰겠다는 뜻과 동일합니다.
as 문법은 이럴 때 쓰도록 합시다.
1. 왜 타입에러가 나는지 정말 모르겠는 상황에 임시로 에러해결용으로 사용하거나
2. 내가 어떤 타입이 들어올지 정말 확실하게 알고 있는데 컴파일러 에러가 방해할 때
⚡️옛날 Type Assertion 문법
as 키워드 대신 <> 이런 괄호를 이용했습니다.
let 이름 :number = 123;
(이름 as string) + 1; //현재문법
<string>이름 + 1; //옛날문법
위에 있는 두 줄의 코드는 똑같은 의미입니다.
다만 html과 js가 혼연일체된 리액트에서 사용시 html태그 이런거랑 헷갈릴 수 있기 때문에 지금은 그냥 as 키워드를 주로 씁니다.
< as는 이럴 때 유용 >
가끔 타입을 강제로 부여하는 기계를 하나 만들어쓰고 싶은 때가 있습니다.
그럴 때 함수에 데이터를 넣으면 as 타입명을 붙여서 return 하는 함수를 만들어서 사용하면 됩니다.
type Person = {
name : string
}
function 변환기<T>(data: string): T {
return JSON.parse(data) as T;
}
const jake = 변환기<Person>('{"name":"kim"}');
⚡️class 만들 때 타입지정 가능
class Person {
name :string;
age :number;
constructor (a :string, b :number){
this.name = a;
this.age = b;
}
}
필드 값으로 name, age가 미리 정의되어있어야 constructor 안에서도 사용가능합니다.
'TypeScript' 카테고리의 다른 글
[TypeScript] 타입을 파라미터로 입력하는 Generic (1) | 2022.12.30 |
---|---|
[TypeScript] 타입과 변수 import export namespace 하는 방법 (0) | 2022.12.30 |
[TypeScript] Narrowing 할 수 있는 방법 ( typeof, in연산자, instanceof ) (0) | 2022.12.30 |
[TypeScript] 함수 rest 파라미터, destructuring 할 때 타입지정 (0) | 2022.12.30 |
[TypeScript] Typescript 설치 셋팅 (Vue, React 포함) (1) | 2022.12.28 |