타입 스크립트 기본
let 변수명 :타입지정 =
let 변수명:string[]
let 변수명:{key:string}
let 변수명: string | number
type 키워드를 사용하면 타입을 변수처럼 사용 가능하다,
type 변수타입 = string
let 변수명: 변수타입 = 'hello-kk'
내가 만든 타입도 가능한데, 이 경우에는 타입으로 넣어준 값만 대입 가능하다.
type helloType = 'hello-kk'
let 변수명: helloType = 'hello-kk'
함수 타입
function 함수명(x :string) :void{
console.log(x)
}
함수에서 타입이 확실하지 않은 경우, narrowing 또는 assertion 문법을 사용해야 오류가 없다.
if (typeof x === 'string')
배열에 어떤 타입의 요소가 들어올지 지정하는 방법
type MyInfo = [string, boolean];
let me:MyInfo = ['hello-kk', true]
tsconfig.json 설정
https://www.typescriptlang.org/tsconfig
타입 예측이 어려운 경우, 방법
Union type
- 배열 안에 들어갈 타입이 여러가지일 때
let myArray:(number|string)[] = ['1',2]
unknown
- 모든 타입의 자료를 넣을 수 있으며 데이터를 입력하더라도 타입은 변하지 않는다.
- 다음의 차이
(1) 변수1의 경우 원소 타입이 둘중 하나에 해당한다. 모든 원소가 number 또는 string 가능하다. [1,'2',3]
(2) 변수2의 경우 타입과 위치가 지정됨=>알고보니 Tuple 타입. [1,'2']
let 변수1 : (number|string)[]
let 변수2 : [number, string]
Tuple 옵션도 가능하지만, 옵션('?')은 가장 뒤에서부터 앞으로 오는 순서로만 가능. 중간에 못함. 요소가 2개 이상인 경우 맨앞에 못씀
type Num = [number, number?, number?];
let 변수a: Num = [1];
let 변수b: Num = [1, 2];
let 변수c: Num = [1, 2, 3];
튜플이지만 뒤에 몇개가 올지 모를때
let 배열1 = [6,7,8]
let 배열2 :[number, number, ...number[]] = [4,5, ...배열1]
함수 안에 파라미터로 튜플을 사용하는 경우
- 일단 파라미터 첫번째, 두번째, 세번째 등 몇개가 총 들어올지 모르는 경우. 해본 내용처럼 하면 안된다. 유연하지 않음
- 수정한 내용처럼 rest parameter를 사용해야 한다.
(착각한점)
"n번째 파라미터"라고 생각해서 컴마로 들어오니까, 단순하게 생각했는데 그러면 안되고, 들어오는 파라미터 전부를 하나의 배열이라고 생각해야 한다!
// 내가 해본 내용
function 함수예제(x:string,y:boolean,...z:(number|string)[]){
...
}
// 수정
function 함수예제(...x:[string,boolean,...(number|string)[]]){
...
}
함수의 타입 지정
- 파라미터 타입을 받을수도 있고 안 받을수도 있는 경우(옵셔널)
function 함수명1(x?: string){}
function 함수명2(x: string|undefined){}
- 둘의 차이?
(1) string 또는 값을 받지 않음. 값이 들어올 수 도 있고 안들어올 수도 있다.
(2) string 또는 undefined를 받음. 어쨌든 값이 들어옴
예시
- typeof는 string을 결과로 내준다. 그렇지만 타입이 있는지 없는지가 중요하다면 if(tmp)만으로도 가능하다.
function hello(tmp?: string | number): void {
if (typeof tmp == "number") {
console.log("number :", tmp);
}
if (typeof tmp == "string") {
console.log("string :", tmp);
}
}
hello(1);
hello("hello-kk");
Narrowing & Assertion
- Narrowing: Union 타입에서, 여러 타입 중 타입 하나를 정해주는 것
Assertion
- as 키워드를 사용
하지만, Assertion보다 Narrowing을 사용해서 더 엄격한 타입 체크를 하도록 하자.
Type Aliases
readonly 키워드
readonly 키워드를 사용하면 primitive 타입(object)에서도 내부 key의 value 값을 바꿀 수 없다. const 와 비슷하게 생각
INTERSECT로 여러 타입 모두 쓰기 union과 다르게 모두 쓸 수 있다: 타입1 & 타입2
type 키워드와 interface 키워드의 차이?
- type는 재정의 불가, interface는 재정의 가능
as const
1. object value로 타입을 바꿈
2. object의 모든 속성을 readonly로 바꿈
함수 타입 지정(함수 type alias)
1. 화살표함수만
2. 매개변수:타입 => return 타입
타입 검사
typeof 대신, instanceof 써보기
타입스크립트에서 HTML 타입 차이
(1) Element
(2) HTMLElement
(3) HTMLAnchorElement
Class에서의 타입스크립트
(주의)
1. constructor에서 this 키워드를 쓰기 위해서는 constructor 전에 정의해야 함
2. 메서드는 function 키워드 필요하지 않음
3. 함수랑 다르게 class 이름 뒤에 ()가 없다.
4. constructor는 객체를 생성
class Car {
model;
price;
constructor(x: string, y: number) {
this.model = x;
this.price = y;
}
sell():number {
return this.price / 2
}
}
만약 생성자에 갯수를 예측할 수 없는 파라미터가 들어온다면, 타입을 어떻게 지정할까?
constructor(...arr: (number | string)[]) {
...
}
Object interface로 타입 지정시 중복되는 타입이 있다면,
interface Student {
name: string;
}
//수정 전
interface Teacher {
name: string;
age: number;
}
//수정 후
interface Teacher1 extends Student {
age: number;
}
만약 중복되지 않는다면
interface Student {
name: string;
}
interface Teacher {
age: number;
}
let 변수: Student & Teacher = {name:'hello',age:00 }
type와 interface 차이
interface
(1) 중복 선언이 가능, extends 한 것 같은 효과
type
(1) 중복 선언이 불가능
배열 object 타입이라면?
interface 아이템{
name:string;
level:number
}
let 인벤토리:아이템[] = [{... },{... }]
object 안에 함수를 넣는 방법
interface 예제 {
plus: (x: number, y: number) => number;
minus: (x: number, y: number) => number;
}
export let 예: 예제 = {
plus: function (x, y) { //plus(x,y){ return x + y; } 동일
return x + y;
},
minus: function (x, y) { //minus(x,y){ return x - y; } 동일
return x - y;
},
};
Destructing 문법을 사용해서 인자를 전달하는 경우 타입을 주는 방법
function 함수({student, age}){
}
함수({ student : false, age : 0 })
//타입 지정
function 함수({student, age}:{student:boolean, age:number}){
..
}
배열도 Desctructing 문법이 가능. key가 없기 때문에 순서대로 이름을 임의로 정해주면 그대로 사용가능하다.
Narrowing 방법
if문
(1) 값이 있고 타입이 있는지 확인
(2) object 안에 key가 있는지
- 예: if ( 'name' in person)
(3) class의 경우 instanceof로 부모 클래스 검사 가능
(4) literal type활용
- 예:
type Person = { name:'kk', age:0}
function 함수(x: Person){
if ( x.name === 'kk' ){
...
}
}
Never Type
(1) 파라미터 타입이 never인 경우: narrowing을 잘못한 경우이니, 코드 수정하기.
(2) return 타입이 never인 경우: 함수에서, throw 혹은 while의 무한루프일 때(=종료 지점에 닿지 않을 때) never가 return 된다.
(3) 반환 타입을 설정하지 않은 경우, 함수 표현식에서(2)의 경우를 만나면 never를 리턴하고, 함수 선언식이라면 void를 return
Class에서 public, private
(1) private 키워드를 사용하면 class 내부 메서드로만 해당 속성이 변경 가능하다.
(2) 생성자에 할당하지 않아도 사용 가능하다.
class Student {
constructor ( public name :string ){
//할당하는 부분이 없어도 됨
}
}
Class에서 protected, static
(1) protected: extends한 하위 클래스에서 변경이 가능 <-> private: 하위 클래스에서 변경 불가능
namespace
- type으로 선언한 변수이름이 여러개가 중복된다면?
namespace JSstudyFirst {
export type Js = string;
}
namespace JSstudySecond {
export interface Js { student: string} ;
}
let study:JSstudyFirst.Js = 'JavaScript'
Generic 활용방법
- 단순히 타입을 파라미터로 전달한다고 생각하면 안된다. 구체적인 예시를 알아야 함!
(1) union, any, unknown 타입일 때, 타입을 바꿔줘야 한다=> 그렇지 않으면 타입이 변하지 않아서 연산등이 불가능
- narrowing 을 사용하거나
- Generic을 활용: 보통 <T>라고 하고, 인수는 2개 이상도 가능
function 함수<T>(x: T[]): T {
return x[0];
}
console.log(함수<string>(["hello", "kk"]));
console.log(함수<number>([1, 2]));
Generic 타입 제한 extends
- extends한 타입만 가능
예: 함수<number>('1')하니까 '1'에 에러뜸
예: 함수<string>하니까, 에러뜸: Type 'string' does not satisfy the constraint 'number'
function 함수<MyType extends number>(x: MyType) {
return x - 1
}
Class 에서 사용하려면,
- new로 생성할 때 타입을 지정해주어야 한다.
- 처음 클래스를 만들때도 제네릭을 적어주기
class Student<T> {
name;
constructor(name: T) {
this.name = name;
}
}
let a = new Student<string>('hello-kk');
타입스크립트로 JSX 타입 지정이 가능하다
let hello버튼:JSX.Element = <button>hello</button>
index signatures
- 몇개의 속성이 들어올지 모르는 경우이지만 모든 키-값의 타입이 정해진 경우 사용가능
interface ObjType {
[key: string]: string,
}
let obj: ObjType = {
name:'kk'
id:'hello-kk'
}
Recursive Index Signatures
keyof 연산자
- object의 key가 타입이 된다.
아래 예시에서 PersonKeyType은 'age'|'name' 타입이 됨=> literal type
interface Person {
age: number;
name: string;
}
type PersonKeyType = keyof Person;
Mapped Types
- 속성명은 그대로고 다른 타입으로 바꿔주는 변환기가 됨.
- 아래의 예시를 보면 속성명은 그대로되, :string; 으로 인해 모든 value가 string이 됨.
- 엄청 많은 속성을 갖고있을 때 유용하게 쓰임
(주의)
- type TypeChanger <T> = { } 로 적어주어야 한다. (interface와 사용시 차이)
- 제네릭 여러개 쓸 수 있음
type Student = {
name: number,
id : boolean,
};
type TypeChanger <T> = {
[key in keyof T]: string;
};
type 타입변환기 = TypeChanger<Student>;
let student :타입변환기 = {
name: 'kk',
id : 'hello-kk',
}
type TypeChanger2 <T,valueT> = {
[key in keyof T]: valueT
};
★타입과 삼항연산자★
(주의): 어렵다..
- Student라는 타입은 T를 타입으로 갖는데, T는 배열일수도 있고, 아닌 경우에는 해당 타입을 줌
- 내가 만든 타입이지만 제네릭을 썼다.
- 그리고 extends를 써서 타입을 제한함. (나는 typeof T === [] 라고 했는데.. 안됨, Array.isArray()를 쓰려고 했음)
- 삼항연산자에서 아무 타입의 배열을 어떤걸로 표현해야 할지 몰랐음
type Student<T> = T extends any[] ? T[0] : any
let student1 :Student<string[]>; // 결과 => 타입: string
let student2 :Student<number>; // 결과 => 타입: any
infer 키워드
아직 어려운 내용들, 다시 모아서 정리하기
- instanceof 의 사용법
- type literal의 Narrowing 사용법
- 타입스크립트에서 HTML 타입 차이
(1) Element
(2) HTMLElement
(3) HTMLAnchorElement
type literal
- 해당 string 또는 number 그 자체가 타입이 된다.
- 해당 타입이 값이 된다.
type MyType = 'hellokk';
//불가능
let student: MyType = "hello";
//가능
let student:MyType = 'hellokk';
//불가능
console.log(typeof student === 'hellokk');
//가능
console.log(typeof student === 'string');
'Front-End > TypeScript' 카테고리의 다른 글
event Type (0) | 2023.03.15 |
---|---|
제네릭<T> (0) | 2023.03.15 |
TypeScript 제네릭 (0) | 2023.02.23 |
(책) 알아서 잘 딱 깔끔하고 센스있게 정리하는 TypeScript 핵심 개념 (0) | 2023.01.19 |