TypeScript is "superset" to Javascript.
자바스크립트는 타입에 관대하다.
5 - '3' 이렇게 숫자와 문자를 연산해도 알아서 타입을 바꿔서 연산해주는데,
이는 자바스크립트가 Dynamic typing(동적타이핑)을 지원하는 언어이기 때문이다.
이런 Dynamic typing은 큰 프로젝트 시 type과 관련된 버그들이 많이 발생하면서 단점이 된다.
이런문제점을 해결해주는 언어로 타입스크립트가 사용된다.
타입스크립트는 자바스크립트의 superset이라고 불린다.
자바스크립트를 기반으로 하는 프로그래밍 언어, 혹은 자바스크립트의 확장이라고 할 수 있다.
핵심언어는 여전히 자바스크립트이다!
TypeScript adds static typing to JavaScript.
타입스크립트는 자바스크립트에 정적 타이핑을 추가해준다.
자바스크립트는 동적타입의 언어로 런타임에서 오류를 발견할 수 있는 반면,
타입스크립트는 정적타입의 컴파일 언어로 compiler 혹은 babel을 통해 js코드로 변환되며,
compile 단계에서 에러를 바로 포착할 수 있으므로 보다 안정성있는 코드를 작성할 수 있다.
( = 실행하지 않고도 코드 내 오류를 잡는다)
타입스크립트가 중요한 이유
1. 실행 전 개발 단계에서 작성과 동시에 분석을 함으로써 오류를 찾을 수 있다.
( TS는 개발용, 개발 후엔 JS로 컴파일링 )
The key difference is :
JavaScript uses "dynamic types" (resolved at runtime),
TypeScript uses " static types" (set during development(compile))
기본 핵심 타입
> 변수 생성 시
const 이름 : string = 'kim'
이름이라는 변수는 string 타입이 되며, 숫자로 할당하려고하면 에러가 발생하게된다.
자주쓰이는 primitive types : string, number, boolean(true, false)
Array
1. 타입뒤에 [ ] 대괄호를 하거나
2. 제네릭 배열 타입 : Array<elemType>
const member1: string[] = ["kim", "park"];
const member1: Array<string> = ["kim", "park"];
: but 굳이 type지정 안해도 변수 생성시 ts가 타입 자동으로 부여한다.
Object
const member2: { age: number } = { age: 20 };
Any
: 아무 자료나 집어넣을 수 있는 타입 (비상시 쓰는 변수 타입체크 해제기능 같은 용도)
타입검사를 하지 않고, 컴파일에 그냥 통과될 수 있도록 지정
( 타입을 일부만 알고 전체를 알지 못할 때 유용 )
: 타입스크립트의 기능을 사용하지 않고 바닐라 자바스크립트를 쓰는 것과 다를바 없게 되므로 가능한 사용하지 않는것이 좋다.
> unknown
: 모든 타입을 집어 넣을 수 있지만 any보다는 제약있음
( 아직 뭘 집어넣을지 모르는데 약간의 안전성 필요할 때 )
let 이름: any = "kim";
let 이름: unknown = "kim";
이름 = 123;
이름 = undefined;
이름 = [];
//any, unknown 둘다 에러안남
let 이름 : unknown;
//다른곳에 집어넣으려고하면 에러발생 (any는 에러 안남)
let 변수 : stirng = 이름;
let 변수 : boolean = 이름;
let 변수 : number = 이름;
타입스크리트는 정확하고 확실한걸 좋아한다.
let 이름: unknown;
//에러발생 (any는 발생안함)
이름[0];
이름 - 1;
이름.data;
확실하지않은 타입에 뺄셈하고 그러면 에러발생!
.name이런건 object만 할 수 있어..에러발생!
Void
: 어떤 타입도 존재하지 않음. ( any의 반대 )
보통 함수에서 반환값이 없을 때 사용.
null, undefined만 할당 가능.
let unusable: void = undefined;
unusable = null; // 성공 `--strictNullChecks` 을 사용하지 않을때만
Never
절대 발생할 수 없는 타입
함수 표현식이나 화살표 표현식에서 항상 오류를 발생시키거나 절대 반환하지 않는 반환 타입으로 쓰인다.
1) return 하지않고 (js 함수 밑엔 return undefined라는 코드가 실은 있어서 2)만 충족되면 됨)
2) 함수 실행이 끝나지 않아야한다. (endpoint가 없어야한다.)
// while은 조건식이 true이면 계속 내부코드를 실행하라
function 함수(): never {
while (true) {
console.log("hi");
}
}
function 함수2(): never {
throw new Error("error");
}
함수선언문 아무것도 return 하지않고, 끝나지도 않을경우
void 타입이 자동으로 return type으로 할당, 함수표현식은 never 타입이 할당
function 함수(){
throw new Error()
}
let 함수2 = function (){
throw new Error()
}
Enum
기본적으로 enum은 0부터 시작하여 구성요소들의 번호를 매긴다.
enum Color {Red, Green, Blue}
let c: Color = Color.Green;
// 1
모든 값들은 수동으로 설정이 가능하다.
enum Color {Red = 1, Green, Blue = 4}
let c: Color = Color.Green;
매겨진 숫자로 해당 요소를 찾을 수 있다.
enum Color {Red = 1, Green, Blue}
let colorName: string = Color[2];
console.log(colorName);
// Green
null & undefined
: undefined와 null 둘 다 각각 자신의 타입이름으로 undefined와 null을 사용한다.
void처럼 그 자체로 유용한 경우는 거의 없다.
: --strictNullChecks를 사용하면, 이 둘은 오직 any와 각자 자신들 타입에만 할당 가능하다. (undefined는 void도 가능)
이것은 많은 일반적인 에러를 방지하는 데 도움을 준다.
null 이나 undefined 처리를 어떻게할지 if문으로 짤 경우가 많이생긴다.
이 때, &&을 활용하면 if문을 생략가능하다.
&& 2개가 참이면 전부 참으로 판정하는 논리연산자인데, 여러개 사용시
자료형을 넣으면 처음등장하는 falsy값을 찾아주고 그게 아니면 마지막 값을 남겨준다.
(falsy : null, undefined, NaN 등)
function And(strs: string | undefined) {
if (strs && typeof strs === "string") {
console.log("ss");
}
}
And("s");
// 출력 : ss
변수가 undefined면 if문 실행 X ( if 조건식안에 falsy 값 남으면 if문 실행되지않음)
변수가 string 타입이면 if문 실행O
Tuple Type
길이와 type이 고정된 불변구조의 array
( 튜플 타입 변수는 정확히 명시된 개수 만큼의 원소와, 각원소의 타입이 정확히 지정된 배열을 가져야한다.)
const person : {
...
role : [number, string]
} = {
...
role : [2, 'author']
}
단, Array prototype의 메소드를 통해 조작되는 것은 원소의 개수를 보장하지않는다.
* push
const person : {
...
role : [number, string]
} = {
...
role : [2, 'author']
}
person.role.push("admin");
//가능
person.role = [0, "admin", "user"];
* rest parameter
: 일반 파라미터에서 array로 담겨온다는 기능상 차이가 있다.
function 함수7(...x: [string, number]) {
console.log(x);
}
함수7("hi", 4);
* spread
let arr = [1, 2, 3];
let arr2: [number, number, ...number[]] = [4, 5, ...arr];
Union type
: 타입 2개를 합친 새로운 타입을 만든다.
or 연산자 같이 'A이거나 B이다'
> 할당하는 순간 타입은 string 또는 number중 하나로 변한다.
const 나이 : string | number = 100
const 나이 : (string | number) = 100
//(에러!!!!)괄호없으면 number나 string중 하나로 통일되어야한다.
let members : number | string[] = [1,'2',3];
//(에러해결) number 혹은 string 둘중하나!
let members : (number | string)[] = [1,'2',3];
const combine = (input: number | string, input2: number | string) => {
let result;
if (typeof input === "number" && typeof input2 === "number") {
result = input + input2;
} else {
result = input.toString() + input2.toString();
}
return result;
};
🔻 union type 에러발생시 2가지 해결방법
1. Type narrowing
2. Assert
Literal Type
➡️ 특정 글자나 숫자만 가질 수 있게 제한을 두는 타입
( 파라미터값 지정해 놓으면 자동완성으로 오타방지 가능! )
: obejct 구분할 일 많을 때 literal type 으로 각각 유티크한 자료를 만들어두면 편하게 narrowing 가능하다.
// 파라미터에 hello만 입력할 수 있고, return 값은 1과 0만 올수잇는 함수
function 함수(x : 'hello') : 1 | 0 {
return 1
}
// 가위,바위,보 문자들만 파라미터로 입력할 수 있고, 가위바위보 array만 return 할 수 있다.
function game(x: "가위" | "바위" | "보"): ("가위" | "바위" | "보")[] {
return ["가위"];
}
const combine = (
input: number | string,
input2: number | string,
resultConversion: "as-number" | "as-string"
) => {
let result;
if (
(typeof input === "number" && typeof input2 === "number") ||
resultConversion === "as-number"
) {
result = +input + +input2;
} else {
result = input.toString() + input2.toString();
}
return result;
};
// resultConversion이 'as-number'이므로 33을 숫자로 변환하여 연산
console.log(combine(1, "33", "as-number"));
//34
// wheel 의 개수로 구분
type Car2 = {
wheel: "4개";
color: string;
};
type Bike = {
wheel: "2개";
color: string;
};
function 함수(x: Car2 | Bike) {
if (x.wheel === "4개") {
console.log("이 차는 " + x.color);
} else {
console.log("이 바이크는 " + x.color);
}
}
Type Aliases
➡️ 타입을 여러가지 써야할 때 길어서 보기싫거나, 나중에 또 사용하고싶을 때 변수에 담아서 사용한다.
: 타입 키워드는 재정의가 불가능하다. 보통 대문자로 시작하거나 뒤에 type이라고 붙여서 작명해준다.
: Alias는 새로운 type 변수를 생성하는 것이 아니라, 정의한 타입에대해 쓰기쉽게 새로운 별칭을 부여하는 것과 같다.
1. 변수에 저장
// type 타입변수명 = 타입종류
type 저장 = string | number | undefined; let 변수1 : 저장 = 1;
2. Obejct
// type 키워드 쓰지않을 때 코드
let 학생: {
name: string,
age: number
} = {
name: "kim",
age: 23,
};
// type Aliases
type 사람 = {
name: string;
age: number;
};
let 학생: 사람 = { name: "kim", age: 20 };
3. function
1) 함수타입은 arrow function으로 만든다
type 함수타입 = (x: string, y: number ) => number;
2) function 함수 : 함수타입 () {} 이런식으로는 불가능하다.
함수표현식에 type alias 사용가능.
let 함수: 함수타입 = function (x) { return 10; };
// plusOne, changeName 함수를 object 자료에 넣은형태
// arrow, 일반함수 전부 넣을 수 있다. type은 따로 만들어서 할당해준다.
let 회원정보: Member = {
name: "kim",
age: 30,
plusOne (x) {
return x + 1;
},
changeName: () => {
console.log("hi");
},
};
type Member = {
name: string;
age: number;
plusOne: (x: number) => number;
changeName: () => void;
};
🔻 타입이 전부다 필요하지 않다면, 선택사항인것은 ? 물음표 연산자를 추가해준다.
( 물음표는 'undefiend 타입도 가질수있다'라는 뜻 )
type 사람 = { name: string; age?: number; };
🔻 타입 여러개를 합칠 수 있다.
- OR 연산자로 union type
type Name = 'string';
type Age = 'number';
type New = Name | Age;
- AND 연산자로 object extend
type alias & type alias
type alias & { name : string } 등..
type PositionX = { x: number };
type PositionY = { y: number };
type Extend = PositionX & PositionY;
let 좌표: Extend = { x: 1, y: 2 };
type Obj3 = {
name: string;
phone?: number;
email?: string;
};
type Obj4 = Obj3 & { 미성년: boolean };
let 회원가입정보: Obj4 = {
name: "kim",
phone: 123,
미성년: true,
};
Type Narrowing & Assertion
Type Narrowing
: typeof, in, instanceof 등 타입을 하나로 확정지을 수 있는 코드로 작성한다. ( defensive한 코딩 )
if문 마지막에 else 없으면 에러발생 ( return 하지않는 조건문 있으면 버그생길 수 있어서 )
typeof 변수 ( string, number, object 이런 것만 구분)
속성명 in 오브젝트자료 ( 서로 배타적인 속성 있을 때 )
자식 instanceof 부모
Literal type ( object 구분할 때 )
function cal ( x : number | string) {
return x+1
}
// 에러발생
function 내함수(x: string | number) {
if (typeof x === "number") {
return x + 1;
} else if (typeof x === "string") {
return x + 1;
} else {
return 0;
}
}
* if ( 변수 != null ) 이렇게 조건식쓰면 null, undefined 두개 동시에 거를 수 있다.
🔻in 연산자
: 서로 다른 유니크한 속성들을 가지고있는 object를 파라미터로 받으면,
if ( 이 파라미터가 a라는 속성을 Object에서 가지고 있나) = if ( a in Object )
이런 if문으로 narrowing 가능하다.
type Fish = { swim: string };
type Bird = { fly: string };
function 함수(animal: Fish | Bird) {
if ("swim" in animal) {
return animal.swim;
}
return animal.fly;
}
🔻 class로 생성된 object
class로부터 new 키워드로 생성된 obejct는 instanceof 키워드로 부모 class를 검사하여 Narrowing 할 수 있다.
let Date1 = new Date();
if (Date instanceof Date) {
console.log("true");
}
Assertion
: 변수명 as (type지정)
union type같이 복잡한 타입을 하나의 정확한 타입으로 줄인다.
function 함수 (x: number | string) {
let arr: number[] = [];
arr[0] = x as number;
}
함수(123);
//함수('123')해도 에러발생안함
🤷🏻♀️ as number로 지정하고 string 입력하면 ?
: as는 그냥 숫자쓸거라고 주장만하는거지 실제로 type을 바꿔주는건 아니어서 string으로 출력된다.
위의 예시에 적용하자면 함수('123') 입력하면 124출력이 아니라 '1231'로 출력된다.
즉, as는 편하지만 정확하게 코드를 짜려면 narrowing을 써야한다.
1. 왜 타입에러 나는지 죽어도 모르겠을 때 임시 에러해결용! (남코드 수정할때 비상용으로?!)
2. 어떤 타입이 들어올지 확실히 알고 있는데 컴파일러 에러가 방해할 때 쓴다.
Function type 지정
두 군데 타입지정 가능
1. 파라미터 (함수로 들어오는 자료)
2. return (함수에서 나가는 자료)
function 함수 (x:number) :number {
return x *2
}
파라미터가 옵션일 경우
: 파라티터 없이 쓸 때 parameter ? 로 표시해줘야 에러가 나지 않는다.
parameter? : type
parameter? : type | undefined 랑 같은 의미 (파라미터가 정의가 안되면 자동으로 undefined가 됨)
function 함수2(x?: number) {}
//number | undefiend랑 같은 뜻
함수2(); //가능
함수2(2); //가능
Readonly
const 변수는 속성을 재할당할 수 없다.
const name = 'kim';
name = 'Lee'
//에러발생
하지만, object를 const에 집어넣으면 object내부 변경가능하다.
const는 재할당만 막아주지 object 내부 속성 바꾸는 것 까지는 관여하지 않는다.
object 속성을 바뀌지않게 막고싶다면 readonly를 사용한다.
type Animal = {
readonly name : string
}
let 동물 : Animal = {
name : 'kiwi'
}
동물.name = 'banana' //에러
💥 readonly는 컴파일시 에러를 발생시키는 것일 뿐, 변환된 js파일에서는 속성이 잘 바껴버린다!
as const
typescript 3.4부터 일일이 타입을 선언하지 않아도 컴파일러가 자동으로 타입을 추론한다.
let은 변수값을 바꿀 수 있어서, 좀 더 포괄적인 primitive type으로 추론되고,
let hello = 'world';
// let hello : string
const는 변경이 불가능하므로, literal type으로 'world'가 추론된다.
const hello = 'world';
// const hello : 'world'
🔻 const assertion (타입 단언하기)
let 변수도 const 처럼 literal type으로 추론하고 싶을 때, as const를 사용한다.
( 강하게 제한하고 싶을 때 : 타입을 object의 값으로 바꾸고, readonly로 바뀐다. )
let hello = 'world' as const;
// let hello : 'world'
또한, const에서 object안의 value값을 literal로 관리하고싶을 때
const animal = {
cat : 'kiwi',
dog : 'banana'
}
//cat : stirng, dog : string
const animal = {
cat : 'kiwi',
dog : 'banana'
} as const;
//cat : 'kiwi', dog : 'banana'
let student = {
name : 'kim'
} as const;
function 함수(a : 'kim') {
}
함수(student.name)
//as const를 안했을 땐 student.name이 string이므로 오류발생
출처: https://manon-kim.tistory.com/entry/TS?category=1064633 [MANON]
'Archive' 카테고리의 다른 글
[GIT] git 기본사용 reset / revert / merge / rebase (0) | 2022.05.15 |
---|---|
[React] React Hook Form (0) | 2022.05.08 |
[TIL] GraphQL & Apollo (0) | 2022.04.24 |
[TIL220410] PlanetScale (serverless DB platform) (0) | 2022.04.10 |
[TIL220407] Tailwind CSS (0) | 2022.04.07 |