🔥 feat: TIL 노트 추가
📌 Type 시스템
└ 명시적 정의(변수 선언 시 타입 정의)
let a: boolean = "x"
→ 🚫 boolean 타입에 string타입 할당 불가 알림
└ 변수만 생성(타입 추론)
let b = "hello"
→ b가 string 타입이라고 추론
b = 1
→ 🚫 string 타입에 number타입 할당 불가 알림
----------------------------------------------------------------------------
📌 Types of TS(기본)
✅ 배열: 자료형[]
✅ 숫자: number
✅ 문자열: string
✅ 논리: boolean
✅ optional
const player : {
name: string,
age?:number
} = {
name: "nico"
}
❌ player.age가 undefined일 가능성 알림
if(player.age < 10) {
}
⭕ player.age가 undefined일 가능성 체크
if(player.age && player.age < 10) {
}
❗ ?를 :앞에 붙이면 optional
✅ Alias(별칭) 타입
type Player = {
name: string,
age?:number
}
const player : Player = {
name: "nico"
}
⭐ 함수에서는 어떻게 쓸까
type Player = {
name: string,
age?:number
}
function playerMaker1(name:string) : Player {
return {
name
}
}
const playerMaker2 = (name:string) : Player => ({name})
const nico = playerMaker1("nico")
nico.age = 12
----------------------------------------------------------------------------
📌 Types of TS(part II)
✅ readonly 사용하기
type Player = {
readonly name:string
age?:number
}
const playerMaker = (name: string): Player => ({name})
const nico = playerMaker("nico")
🚫 nico.name = "aa"
const numbers: readonly number[] = [1, 2, 3, 4]
🚫 numbers.push(1)
❗ readonly가 있으면 최초 선언 후 수정 불가
⇒ immutability(불변성) 부여
but, javascript에서는 그냥 배열
✅ Tuple
정해진 개수와 순서에 따라 배열 선언
const player: [string, number, boolean] = ["nico", 1, true]
❗ readonly도 사용가능 ⇒ readonly [...] 형태
✅ undefined, null, any
any: 아무 타입
undefined: 선언X 할당X
null: 선언O 할당X
----------------------------------------------------------------------------
📌 Types of TS(part III)
✅ unknown
let a:unknown
if(typeof a === 'number'){
let b = a + 1
}
if(typeof a === 'string'){
let b = a.toUpperCase()
}
🚫 let b = a + 1
✅ void
아무것도 return하지 않는 함수에서 반환 자료형
function hello() {
console.log('x')
}
const a = hello()
🚫 a.toUpperCase()
✅ never
함수가 return하지 않을 때
function hello():never {
throw new Error("zzz")
🚫return "a"
}
function temp(name:string|number):never {
if(typeof name === "string"){
name
} else if(typeof name === "number"){
name
} else {
name
}
}
if 안에서는 string형의 name 반환
else if 안에서는 number형의 name 반환
else 안에서는 never형의 name 반환
⇒ 즉, 제대로 인자가 전달되었다면 else로 올 수 없음
----------------------------------------------------------------------------
📌 Call Signatures
프로퍼티로 호출 가능한 것을 설명하려면 객체 타입에 Call Signature을 작성할 수 있습니다.
Call Signatures는 다음과 같이 함수의 매개 변수(parameter)와 반환 타입을 지정합니다.
─ 예시 ────────────────────────
type PizzaFunction = {
pizza: string;
(args: number): boolean;
};
function hello(fn: PizzaFunction) {
console.log(fn.pizza, fn(6));
}
https://www.typescriptlang.org/docs/handbook/2/functions.html#call-signatures
----------------------------------------------------------------------------
📌 Function Overloads
동일한 이름에 매개 변수와 매개 변수 타입 또는 리턴 타입이 다른 여러 버전의 함수를 만드는 것을 말합니다.
오버로드 signatures을 작성하여 "다양한 방식으로 호출할 수 있는 함수"를 지정할 수 있습니다.
─ 예시 ────────────────────────
type Add={
(a:number,b:number):number;
(a:number,b:number,c:number):number;
}
const add:Add=(a,b,c?:number)=>{
return a+b;
}
add(1,2)
add(1,2,3)
https://www.typescriptlang.org/docs/handbook/2/functions.html#function-overloads
----------------------------------------------------------------------------
📌 polymorphism(다형성)
❓poly란?
- many, serveral, much, multi 등과 같은 뜻
❓morphos란?
- form, structure 등과 같은 뜻
❗polymorphos = poly + morphos = 여러 다른 구조
concrete type
- number, boolean, void 등 지금까지 배운 타입
generic type
- 타입의 placeholder
─ 예시 ────────────────────────
type SuperPrint = { (arr: T[]): void }
type SuperReturn = { (arr: T[]): T }
const superPrint: SuperPrint = (arr) => {
arr.forEach(i => console.log(i))
}
const superReturn: SuperReturn = (arr) => arr[0]
superPrint([1, 2, false, true])
console.log(superReturn([1, 2, 3, 4]))
----------------------------------------------------------------------------
📌 Generics
제네릭은 C#이나 Java와 같은 언어에서 재사용 가능한 컴포넌트를 만들기 위해 사용하는 기법입니다.
단일 타입이 아닌 다양한 타입에서 작동할 수 있는 컴포넌트를 생성할 수 있습니다.
(구체적인 타입을 지정하지 않고 다양한 인수와 리턴 값에 대한 타입을 처리할 수 있다.)
타입스크립트에서 제네릭을 통해 인터페이스, 함수 등의 재사용성을 높일 수 있습니다.
─ 예시 ────────────────────────
function identity< Type >(arg: Type): Type {
return arg;
}
const identity=< Type extends {} >(arg: Type):Type => {
return arg;
}
let output = identity< string >("myString");
let output = identity("myString");
즉, 컴파일러가 전달하는 인수 유형에 따라 자동으로 Type 값을 설정하기를 원합니다.
https://www.typescriptlang.org/docs/handbook/2/generics.html
💡 그렇다면 그냥 any를 넣는 것과 Generic의 차이는 무엇일까?
type SuperPrint = {
(arr: any[]): any
}
const superPrint: SuperPrint = (arr) => arr[0]
let a = superPrint([1, "b", true]);
a.toUpperCase();
-> any를 사용하면 위와 같은 경우에도 에러가 발생하지 않는다
type SuperPrint<T> = {
(arr: T[]): T
}
const superPrint: SuperPrint = (arr) => arr[0]
let a = superPrint([1, "b", true]);
a.toUpperCase();
-> Generic의 경우 에러가 발생해 보호받을 수 있다
* Call Signature를 concrete type으로 하나씩 추가하는 형태이기 때문!
type SuperPrint = {
(arr: T[], x: M): T
}
const superPrint: SuperPrint = (arr, x) => arr[0]
let a = superPrint([1, "b", true], "hi");
위와 같이 복수의 Generic을 선언해 사용할 수 있다
----------------------------------------------------------------------------
📌 Classes
추상(abstract) 클래스
추상 클래스는 오직 다른 클래스가 상속받을 수 있는 클래스이다.
하지만 직접 새로운 인스턴스를 만들 수는 없다.
─ 예시 ────────────────────────
abstract class User{
constructor(
private firstname:string,
private lastname:string,
public nickname:string
){
abstract getNickname():void
}
}
class Player extends User{
getNickname(){
console.log(this.nickname)
}
}
public: 모든 클래스에서 접근 가능
private: 해당 클래스 내에서만 접근 가능 (자식 클래스에서도 접근 불가)
protected: 해당 클래스와 자식 클래스에서 접근 가능
https://www.typescriptlang.org/docs/handbook/2/classes.html
----------------------------------------------------------------------------
📌 Static Members
클래스에는 static 멤버가 있을 수 있습니다.
이 멤버는 클래스의 특정 인스턴스와 연결되지 않습니다. 클래스 생성자 객체 자체를 통해 액세스할 수 있습니다.
static 멤버는 동일한 public, protected 및 private 과 함께 사용할 수도 있습니다.
─ 예시 ────────────────────────
class MyClass {
static x = 0;
static printX() {
console.log(MyClass.x);
}
}
console.log(MyClass.x);
MyClass.printX();
https://www.typescriptlang.org/docs/handbook/2/classes.html#static-members
----------------------------------------------------------------------------
Interfaces
객체의 모양을 특정해주기 위해 사용합니다. (type도 그러하나 범용성이 더 넓다.)
여기서는 firstName 및 lastName 필드가 있는 객체를 설명하는 인터페이스를 사용합니다.
─ 예시 ────────────────────────
interface Person {
firstName: string;
lastName: string;
}
https://www.typescriptlang.org/docs/handbook/
typescript-tooling-in-5-minutes.html#interfaces
----------------------------------------------------------------------------
📌 implements
implements을 사용하여 클래스가 특정 인터페이스를 충족하는지 확인할 수 있습니다.
클래스를 올바르게 구현하지 못하면 오류가 발생합니다.
implements 절은 클래스가 인터페이스 유형으로 처리될 수 있는지 확인하는 것입니다.
클래스의 유형이나 메서드는 전혀 변경하지 않습니다.
또한 클래스는 여러 인터페이스를 구현할 수도 있습니다. 클래스 C는 A, B를 구현합니다.
─ 예시 ────────────────────────
ex) class C implements A, B { }
interface Pingable {
ping(): void;
}
Pingable가 가진 ping메서드를 구현해줘야 합니다.
class Sonar implements Pingable {
ping() {
console.log("ping!");
}
}
https://www.typescriptlang.org/docs/handbook/2/classes.html#implements-clauses
----------------------------------------------------------------------------
💡 Type Aliases과 Interfaces의 차이점
Type Aliases과 인터페이스는 매우 유사하며 많은 경우 자유롭게 선택할 수 있습니다.
인터페이스의 거의 모든 기능은 type에서 사용할 수 있으며,
주요 차이점은 type을 다시 열어 새 속성을 추가할 수 없는 것입니다.
반면 인터페이스는 항상 확장 가능합니다.
결론: 대부분의 경우 개인 취향에 따라 선택 가능
(인터페이스 사용을 조금 더 추천)
─ 예시 ────────────────────────
type PlayerA = {
name: string;
};
type PlayerAA = PlayerA & {
lastName: string;
};
const playerA: PlayerAA = {
name: "Seong_il",
lastName: "Kang",
};
interface PlayerB {
name: string;
}
interface PlayerBB extends PlayerB {
lastName: string;
}
interface PlayerB {
health: number;
}
const playerB: PlayerBB = {
name: "Seong_il",
lastName: "Kang",
health: 10,
};
console.log(playerA);
console.log(playerB);
https://www.typescriptlang.org/docs/handbook/2/
everyday-types.html#differences-between-type-aliases-and-interfaces
----------------------------------------------------------------------------
⚙️ typescript설치
npm i -D typescript
⚙️ package.json 초기화
npm init -y
⚙️ tsconfig.json설정
디렉터리에 tsconfig.json 파일이 있으면 해당 디렉터리가 TypeScript 프로젝트의 루트임을 나타냅니다.
tsconfig.json 파일은 프로젝트를 컴파일하는 데 필요한 루트 파일과 컴파일러 옵션을 지정합니다.
https://www.typescriptlang.org/docs/handbook/tsconfig-json.html#handbook-content
✅ Target (기본값: ES3)
최신 브라우저는 모든 ES6 기능을 지원하므로 ES6는 좋은 선택입니다. 코드가 이전 환경에 배포된 경우 더 낮은
target을 설정하거나 최신 환경에서 코드 실행이 보장되는 경우 더 높은 target을 설정하도록 선택할 수 있습니다.
ex) 화살표 함수() => this는 ES5 이하이면 함수 표현식으로 바뀝니다.
특별한 ESNext 값은 TypeScript 버전이 지원하는 가장 높은 버전을 나타냅니다.
이 설정은 다른 TypeScript 버전 간에 동일한 의미가 아니며 업그레이드를 예측하기 어렵게 만들 수 있으므로 주의해서 사용해야 합니다.
https://www.typescriptlang.org/tsconfig#target
"build": "tsc" 또는 "npx tsc"
----------------------------------------------------------------------------
✅ lib
타입스크립트에게 어떤 API를 사용하고 어떤 환경에서 코드를 실행하는 지를 지정할 수 있습니다.
(target 런타임 환경이 무엇인지를 지정합니다.)
프로그램이 브라우저에서 실행되면 lib에 "DOM" 유형 정의를 할 수 있습니다.
DOM: window, document 등
ex) "lib": ["ES6","DOM"]
https://www.typescriptlang.org/tsconfig#lib
----------------------------------------------------------------------------
✅ strict
모든 엄격한 타입 검사 옵션을 활성화합니다.
strict 플래그는 프로그램 정확성을 더 강력하게 보장하는 광범위한 타입 검사 동작을 가능하게 합니다.
https://www.typescriptlang.org/tsconfig#strict
----------------------------------------------------------------------------
✅ @ts-check
JavaScript 파일에서 오류를 활성화하려면
TypeScript는 여러 오류를 제공할 수 있습니다.
이러한 오류를 무시하고 싶다면
https://www.typescriptlang.org/docs/handbook/intro-to-js-ts.html#ts-check
✅ JSDoc Reference
JSDoc 주석을 사용하여 JavaScript 파일에 type 정보를 제공할 수 있습니다. (자바스크립트 파일에서 타입 정보를 제공할 수 있다.)
https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html
@param, @returns
─ 예시 ────────────────────────
function stringsStringStrings(p1, p2, p3, p4) {
}
https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#param-and-returns
----------------------------------------------------------------------------
📌 DefinitelyTyped
TypeScript type 정의를 위한 리포지토리입니다.
https://github.com/DefinitelyTyped/DefinitelyTyped
─ 예시 ────────────────────────
@types/node
npm i @types/node -D
----------------------------------------------------------------------------
출처 - https://nomadcoders.co/typescript-for-beginners/lectures/3730 [LIMON029님, sugar님]
좋은 정보 얻어갑니다, 감사합니다.