타입스크립트란?
자바스크립트를 기반으로 한 강력한 정적 타입 지정 언어입니다. 이는 자바스크립트의 모든 기능을 포함하면서도, 추가적인 타입 시스템과 도구를 제공하여 코드의 안정성과 생산성을 높이는 데 도움을 줍니다.
정적 타입 검사
컴파일 단계에서 코드의 타입 오류를 발견할 수 있어 런타임 오류를 줄입니다.
let age: number = 25;
age = "twenty-five"; // 오류 발생: 문자열을 숫자에 할당할 수 없음
자동 완성 및 코드 탐색
타입 정보를 기반으로 IDE에서 자동 완성과 코드 탐색 기능을 제공합니다.
const user = { name: "Alice", age: 30 };
console.log(user.name); // 자동 완성 지원
자바스크립트로 컴파일
타입스크립트는 브라우저나 Node.js에서 실행 가능한 순수 자바스크립트로 컴파일됩니다.
타입 추론
변수의 초기값을 기반으로 타입을 자동으로 추론합니다.
let name = "John"; // 타입이 string으로 자동 추론
자바스크립트 vs 타입스크립트
자바스크립트는 동적타입 언어이기 때문에 변수 타입은 런타임에 따라 결정됩니다.
let value ="hi";
console.log(value.toUpperCase()); // hi
value = 1;
console.log(value.toUpperCase()); // ?
타입스크립트는 정적타입 언어라서 변수의 타입이 컴파일 타임에 결정이 돼서 타입 에러를 미리 발견할 수 있습니다.
장점
크로스브라우징 이슈 해결
크로스브라우징은 크롬, 사파리, 엣지, 파이어폭스 등 모든 브라우저에서 의도한 대로 이상없이 구현되도록 합니다.
컴파일 과정에서 es6+ 문법들을 es5나 es3로 알아서 바꿔주기 때문에 구브라우저에도 대응이 가능합니다.
단점
작은 규모의 프로젝트에서는 불필요할 수 있고 작성해야할 코드가 많아질 수 있습니다.
object 타입
interface PersonType {
name: string;
age: number;
isStudent: boolean;
num?:number // 옵셔널 타입이라 없어도 되고 있어도 될 때 사용합니다.
}
let value: string = 'hello';
const person: PersonType = {
name: '서개발',
age: 10,
isStudent: true,
}
const getPersonAge = (person: PersonType) => {
return person.age;
}
// 사용 예시
console.log(getPersonAge(person)); // 10
array 타입
:배열은 길이 제한이 없고, 모든 요소가 동일한 타입이어야 합니다.
let arr: (number | string)[] = [1, "two", 3];
Tuple
: 배열과 유사하지만, 요소의 타입과 개수가 고정되어 있습니다.
: 각 요소의 타입과 순서를 명확하게 지정해야 하며, 순서가 다르면 에러 발생합니다.
let tuple: [string, number, boolean] = ["홍길동", 15, false];
let person: [string, number] = ["Alice", 30]
: 선택적 요소와 나머지 요소도 지정 가능합니다.
let tupleWithOptional: [string, number?] = ["Alice"];
let tupleWithRest: [string, ...number[]] = ["Alice", 10, 20];
Enum
: 관련된 상수 값들을 하나의 타입으로 묶는 기능입니다.
enum Country { Korea, USA, Japan, China }
let nation: Country = Country.Korea; // 0
명시적으로 값 할당 가능:
enum Country { Korea, USA = 100, Japan, China }
Country.Japan // 101
any 타입
: 모든 타입의 값을 허용하는 특수 타입입니다. 변수에 어떤 값이든 할당할 수 있으며, 타입 검사가 완전히 무시됩니다.
let data: any = "hello";
data = 42; // 에러 없음
data = true; // 에러 없음
void 타입
값을 반환하지 않는 함수의 반환 타입을 나타냅니다. 주로 부수 효과(side effect)만 있는 함수에 사용합니다.\
function logMessage(msg: string): void {
console.log(msg);
}
never 타입
절대 값이 발생할 수 없는(존재하지 않는) 타입입니다. 즉, "불가능"을 표현하는 타입입니다.
//항상 예외를 던지는 함수
function throwError(msg: string): never {
throw new Error(msg);
}
//무한 루프 함수
function infiniteLoop(): never {
while (true) {}
}
//switch문의 exhaustive 체크
type Shape = { type: 'circle' } | { type: 'square' };
function getArea(shape: Shape) {
switch (shape.type) {
case 'circle': return 1;
case 'square': return 2;
default:
const _exhaustiveCheck: never = shape; // 새로운 타입 추가 시 에러 발생
throw new Error('Unhandled case');
}
}
undefined
:변수에 값이 할당되지 않았을 때 자동으로 부여되는 값입니다. 즉, "아직 초기화되지 않은 상태"를 의미합니다.
let a;
console.log(a); // undefined
null
: "값이 의도적으로 없음"을 개발자가 명시적으로 할당할 때 사용하는 값입니다.\
let b = null;
console.log(b); // null
symbol
: ES6에 새롭게 추가되었고, number나 string과 기본 데이터 타입(원시타입)입니다.
변경이 불가능한 유일한 값입니다.
1) 유일성
: Symbol()로 생성된 심볼은 모두 서로 다르며, 같은 문자열을 넘기더라도 서로 다른 심볼입니다.
const sym1 = Symbol('key');
const sym2 = Symbol('key');
console.log(sym1 === sym2); // false
2) 변성
: 생성 후 변경할 수 없습니다. 즉, 값이 고정되어 있으며 변경 불가합니다.
3) 암묵적 형변환 불가
: 심볼은 문자열이나 숫자와 달리 암묵적 형변환이 불가능하며, 문자열로 변환하려면 명시적 호출이 필요합니다.
const sym = Symbol('test');
// console.log(sym + ''); // 에러
console.log(sym.toString()); // 'Symbol(test)'
심볼은 유일한 값을 가지기 때문에 키값으로 사용하면 좋습니다.
//기본 선언
let sym: symbol = Symbol('mySymbol');
//심볼과 객체 프로퍼티
const mySym = Symbol('prop');
const obj = {
[mySym]: 'value'
};
//심볼을 통한 타입 안전성 강화
const sym1: unique symbol = Symbol('unique');
const sym2: unique symbol = Symbol('unique');
// sym1 === sym2 // false, 고유 심볼
unique symbol: 타입스크립트에서 유일한 심볼 타입으로, 선언 시 const 또는 let에 unique symbol을 명시해야 함.
const MY_SYMBOL: unique symbol = Symbol('myUnique');
unknown 타입
: 단어 그대로 타입이 뭔지 알 수 없는 타입입니다.
어떤 값이든 들어올 수 있으니 엄격하게 검사해서 사용해야하며 any타입과 유사하지만, 훨씬 안전합니다.
타입을 특정해주기 전까지는 무언가를 수행하려고 할 때 에러를 내줍니다.
let value: unknown;
value = true;
value = 42;
value = "Hello";
value = [];
value = {};
value = null;
value = undefined;
value = new Error();
value = Symbol("sym");
// 다른 타입 변수에 할당 시 오류 발생:
let value: unknown;
let num: number = value; // 에러!
let str: string = value; // 에러!
function isString(value: unknown): value is string {
return typeof value === 'string';
}
function process(value: unknown) {
if (isString(value)) {
// 타입 가드로 인해 string으로 안전하게 사용 가능
console.log(value.toUpperCase());
} else {
console.log("Not a string");
}
}
함수선언하기
1) 함수 선언식
function add(a: number, b: number): number { // :number은 생략가능
return a + b;
}
타입의 엘리먼트
: 배열의 각 위치에 어떤 타입의 값이 들어가야 하는지 명확하게 제한할 수 있습니다.
type ElementType =[string, number, number];
const menu1:MenuType = ['치킨', 20000,2];
const getReceipt = (arr:MenuType[]):string => {
return '총 얼마입니다';
}
getReceipt([menu1])
2) 함수 표현식
const add = function(a: number, b: number): number {
return a + b;
};
3) 화살표 함수
typescript
const add = (a: number, b: number): number => a + b;
타입추론
: 개발자가 구동으로 명시해야하는 타입 구문의 수를 줄일 수 있습니다.
코드의 전체적인 안정성이 향상됩니다.
어떤 변수에 타입이 다른 값을 재할당하기보다는, 별도의 변수를 사용하는 것이 바람직합니다.
함수를 자체를 인자로 보낼 때 함수타임을 지정을 많이합니다.
const someFunc = (msg:string, showMsg:ShowMsgType) = >{
showMsg(msg.toUpperCse();
}
someFunc('hello;,showMsg);
선택적 매개변수와 기본 매개변수
매개변수 = pararmeter
인자 = argument
const sum = (a:number. b:number) => { //a,b매개변수
return a+b;
}
sum(3,5) // 3,5 인자
선택적 매개변수 Optional Parameter
: 매개변수의 개수는 가변적이라 선택적으로 받을 수 있습니다.
const num =1234;
num.toFixed();
num.toFixed(3);
const func = (nmae:string, job?:string) => { // 선택적으로 받을 인자만 ?를 붙여주면된다.
console.log(name + '' + job);
}
func('김개발');
// 김개발 undefined
기본 매개변수 Default Parmeter
const func = (nmae:string, job = 학생) => { //인자값이 없으면 학생을 반환합니다.
console.log(name + '' + job);
}
func('김개발');
// 김개발 학생
나머지 매개변수 Rest Parameter
: 매개변수의 개수가 가변적일 때 배열 형태로 받아올 수 있습니다.
무조건 파라미터 마지막에 있어야합니다.
const func = (one:number, two: number, ...rest : number[]) => {
console.log(one);
console.log(two);
console.log(rest);
}
func(1,2,3,4,5);
// 1
// 2
//[3,4,5]
유니언 타입
: 여러 타입 중 하나가 될 수 있음을 명시하는 타입입니다.
cosnst func = ( id:string | number) => {
console.log('ID', id)
}
func('1234');
func(1234);
// 'ID', '1234'
// 'ID', 1234
교차타입
: 여러 타입을 모두 만족하는 하나의 타입을 만드는 것입니다.
type Person = {
name:string;
age:number;
}
type Student = Person & {
school:stirg;
}
타입 앨리어스(Type Aliases)
: 번역하면 타입 별칭이라고 하는데 중복되거나 복잡한 타입들은 이름을 지어줘서 재사용합니다.
type Person = {
name:string;
age:number;
}
const user1:Person = {
name:'서개발',
age: 25
}
const user2:Person = {
name:'둥개발',
age: 21
}
유니언 타입으로 타입 앨리어스 주는 방법입니다.
type studentId = number | null;
let id:studentId = null;
교차 타입으로 타입 앨리어스 주는 방법입니다.
type studentId = number | null;
const user1:Person & {
id: studentId;
}
투플 타입으로 타입 앨리어스 주는 방법입니다.
type TupleType = [number, string];
const tuple1:TupleType = [10,'hi'];
타입앨리어스 vs 인터페이스
// 타입 앨리어스
type Person = {
name:string;
age:number;
}
// 인터페이스
interface Person2 {
name:string;
age:number;
}
확장 시
// 타입 앨리어스 교차 형식으로 확장
type Student = Person & {
id : number
}
// 인터페이스 확장
inferface Student2 extends Person2{
id:number
}
타입앨리어스는 같은 이름을 사용하면 에러가 뜨지만, 인터페이스는 에러가 발생하지 않고 합쳐지게 됩니다. => 선언적 확장
타입 앨리어스는 &, 인터페이스는 extends로 확장이 가능합니다.
인터페이스는 동일한 이름으로 정의함으로써 선언적 확장이 가능합니다.
인터페이스는 객체에만 사용이 가능합니다.
리터럴 타입
: 고정된 값을 타입으로 가집니다.
원래같으면 string으로 지정하지만 혈액형은 4가지 종류만 있으니 아래의 코드처럼 리터럴 타입으로 주는 것이 정확합니다.
type BloodType = 'A' | 'B' | 'AB' | 'O'
만약에 위에 있는 코드가 수정될 일이 없으면 뒤에 as const를 붙이면 됩니다.
배열일 때도 수정할 일 없고 고정일 때만 as const를 사용합니다.
유니업타입
인터페이스 주석에 있는 값만 받으려고 했는데 다른 값을 받으면 오류가 날 수 있습니다.
interfacr Item {
code: number; // 280 , 281 , 282 , 283
size:string; // small, medium, large, xlargr
}
const SelectedItem: Item = {
code:0,
size:'XL'
}
그래서 리터럴 타입으로 변경을 하면 오류가 안 생기고 주석도 안 달아도 됩니다.
interfacr Item {
code: 280 | 281 | 282 | 283
size: small| medium | large | xlargr
}
const SelectedItem: Item = {
code:0, // 에러
size:'XL' // 에러
}
클래스
class User {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
greet(): string {
return `Hello, ${this.name}!`;
}
}
const user = new User('Alice', 30);
console.log(user.greet()); // Hello, Alice!
클래스 상속
: 상속을 통해 하위 클래스가 상위 클래스의 프로퍼티와 메서드를 상속받을 수 있습니다.
상위 클래스의 생성자의 호출을 하기 위해 하위 클래스의 생성자에거 super() 메서드를 사용해야합니다.
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
speak(): void {
console.log(`${this.name}이(가) 소리를 냅니다.`);
}
}
class Dog extends Animal {
constructor(name: string) {
super(name); // 부모 생성자 호출
}
speak(): void {
console.log(`${this.name}이(가) 멍멍 짖습니다.`);
}
}
const dog = new Dog('바둑이');
dog.speak(); // 바둑이이(가) 멍멍 짖습니다.
readonly 지정자
: constructor 외부에서 값 할당이 불가능하게 막습니다.
속성(프로퍼티)이나 배열, 튜플, 객체 타입의 값을 "읽기 전용"으로 만들어주는 키워드입니다. 한 번 값이 할당되면 이후에는 변경할 수 없도록 하여, 코드의 **불변성(immutability)**을 보장하고, 실수로 인한 값 변경을 방지할 수 있습니다
class Person {
readonly name: string;
constructor(name: string) {
this.name = name; // 생성자에서만 할당 가능
}
}
const john = new Person('John');
john.name = 'Jane'; // 오류: 'name'은 읽기 전용 속성입니다.
getters / setters
private으로 설정된 프로퍼티를 읽거나 새로운 값을 할당하고 싶을 때는 getters / setters를 사용하면 됩니다.
class User {
private _age: number = 24;
// getter: 값을 읽을 때 사용
get age() {
console.log('Age getter called');
return this._age;
}
// setter: 값을 쓸 때(할당할 때) 사용
set age(value: number) {
console.log('Age setter called');
if (value < 0) {
throw new Error('나이는 0보다 작을 수 없습니다.');
}
this._age = value;
}
}
const user = new User();
user.age = 25; // Age setter called
console.log(user.age); // Age getter called, 25
전역 프로퍼티
: static 키워드를 사용하고 인스턴스를 생성하지 않고도 클래스의 메서드 프로퍼티에 접근이 가능합니다.
class Counter {
static count: number = 0;
static increment() {
Counter.count++;
}
}
// 인스턴스 생성 없이 클래스명으로 접근
console.log(Counter.count); // 0
Counter.increment();
console.log(Counter.count); // 1
const c = new Counter();
// 인스턴스를 통해서는 static 프로퍼티에 접근 불가
// console.log(c.count); // 오류!
추상 클래스
: 클래스, 클래스의 메서드에 abstract 키워드를 사용해서 표현합니다.
추상 메서드는 정의만 되어 있고, 구현은 되어 있지 않습니다.
추상 클래스는 인스턴스를 만들 수 없습니다.
추상 클래스를 상속받은 하위 클래스에서 추상 클래스 내에 정의된 추상 메서드를 반드시 구현해야 합니다.
// 추상 클래스 선언
abstract class Animal {
constructor(private _age: number) {}
get age() {
return this._age;
}
set age(value: number) {
this._age = value;
}
// 추상 메서드: 구현 없음, 반드시 하위 클래스에서 구현해야 함
abstract makeSound(): void;
// 구현된 메서드: 공통 동작 정의 가능
sleep() {
console.log('Zzz...');
}
}
// 추상 클래스를 상속받는 구체 클래스
class Dog extends Animal {
makeSound(): void {
console.log('멍멍!');
}
}
const dog = new Dog(3);
dog.makeSound(); // 멍멍!
dog.sleep(); // Zzz...
// const animal = new Animal(5); // 오류! 추상 클래스는 직접 인스턴스화 불가
오버라이팅(overriding)
: 상위 클래스에서 정의되었던 메서드를 하위클래스에서 재정의하는 것입니다.
상위 클래스에 동일한 이름의 메서드를 무시하고 하위클래스에서 재정의할 필요가 있을 때, 추상 클래스에서 정의한 추상메서드를 구현할 때 사용합니다.
class Person {
sayHello() {
console.log("Hello");
}
}
class Student extends Person {
sayHello(name?: string) {
if (name === undefined) { // 오타: underfined → undefined
super.sayHello();
} else {
console.log('hi ' + name); // 오타: consoel → console
}
}
}
const s = new Student();
s.sayHello(); // Hello
s.sayHello("철수"); // hi 철수
제네릭
단일 타입이 아닌 다양한 타입에서 작동하는 컴포넌트를 작성할 수 있습니다.
사용처에서 타입을 정해서 전달할 수 있습니다.
function identity<T>(arg: T): T {
return arg;
}
// 사용처에서 타입 지정
const a = identity<string>("hello"); // a: string
const b = identity<number>(123); // b: number
const c = identity<boolean>(true); // c: boolean
제네릭 타입 변수
함수나 클래스, 인터페이스에서 타입을 변수처럼 선언해 두고,
함수를 사용할 때(호출 시점에) 원하는 타입을 지정할 수 있도록 해줍니다.
제네릭 타입 매개변수 <T>를 사용하면 함수 호출 시 타입을 지정해 T[] 타입의 배열을 안전하게 처리할 수 있고, any와 달리 타입 체크가 정확하게 이뤄집니다
function identity<T>(arg: T[]): T[] {
console.log(arg.length); // 배열 길이 출력
return arg;
}
let output = identity<number>([1, 2, 3]); // 출력: 3, 반환 타입: number[]
제네릭 타입 매개변수를 두개 사용할 수 있습니다.
function identity<T, U>(arg1: T, arg2: U): [T, U] {
return [arg1, arg2];
}
const result = identity<number, string>(3, 'hi'); // 반환 타입: [number, string]
제네릭 클래스
: 다양한 타입의 데이터를 안전하게 저장하고 관리할 수 있습니다.
number 타입만 저장하는 리스트를 만들고, 숫자 1을 추가한 뒤 결과를 출력합니다.
class List<T> {
data: T[];
constructor(data: T[]) {
this.data = data;
}
add(item: T) {
this.data = [...this.data, item];
}
}
const list = new List<number>([]);
list.add(1);
console.log(list.data); // [1]
제네릭 인터페이스
: 인터페이스 정의 시 타입 매개변수를 사용해, 속성의 타입을 유연하게 지정할 수 있습니다
id를 number 타입으로 지정해 객체를 생성합니다.
interface Person<T> {
name: string;
id: T;
}
let person: Person<number> = {
name: 'asd',
id: 10
};
제네릭 제약 조건
: 제네릭 타입 매개변수가 가질 수 있는 타입의 범위를 제한하는 기능입니다.
기본적으로 제네릭은 모든 타입을 받을 수 있지만, 때로는 특정 속성이나 구조를 가진 타입만 허용하고 싶을 때가 있습니다.
이럴 때 extends 키워드를 사용해 제약을 걸 수 있습니다
interface LengthWise {
length: number;
}
function identity<T extends LengthWise>(arg: T): T {
console.log(arg.length); // 정상: length 속성 접근
return arg;
}
identity({ name: 'se', length: 100 });
타입 단언(as)
타입 추론이 정확하지 않을 때, 혹은 의도와 다르게 추론하고 있을 때, as키워드를 사용해서 타입을 단언해줄 수 있습니다.
아래 코드는 a는 string 타입이니깐 가지고 오라는 뜻입니다.
let a:unknown = "hi";
let b = (a as string).length;
아래 코드는 컴파일러는 myCanvas가 어떤 HTMLElement인지 확실히 모르지만, 개발자가 직접 HTMLCanvasElement라고 단언해 타입 오류를 방지합니다.
const myCanvas = document.getElementById("main_canvas") as HTMLCanvasElement;
타입 서술어(is)
: 특정 값이 원하는 타입임을 타입스크립트에게 알려주는 기능입니다.
isFish 함수는 pet이 Fish 타입인지 런타임에 검사해, 이후 코드에서 타입을 안전하게 좁혀주는 타입 가드 역할을 합니다.
type Fish = { swim: () => void };
type Bird = { fly: () => void };
function isFish(pet: Fish | Bird): pet is Fish { //pet is Fish 타입가드
return (pet as Fish).swim !== undefined;
}
const fish: Fish = { swim: () => console.log("물고기 수영") };
const bird: Bird = { fly: () => console.log("새 날기") };
console.log(isFish(fish)); // true
console.log(isFish(bird)); // false
타입 가드란, 어떤 스코프 안에서 특정 타입을 보장하는 런타임 검사를 수행하는 표현식입니다.
in 연산자
: 자바스크립트에서 객체안에 어떤 속성이 있는지 여부를 확인할 때 in 연산자를 사용합니다.
'swim' in pet 타입 가드를 사용하면 Fish와 Bird 타입을 안전하게 구분해 각 타입의 메서드를 호출할 수 있습니다.
type Fish = { swim: () => void };
type Bird = { fly: () => void };
// 1. 타입 가드 함수
function isFish(pet: Fish | Bird): pet is Fish {
return 'swim' in pet;
}
// 2. 동물 객체
const fish: Fish = { swim: () => console.log("물고기 수영") };
const bird: Bird = { fly: () => console.log("새 날기") };
// 3. 동작 함수
function action(pet: Fish | Bird) {
if ('swim' in pet) {
pet.swim(); // Fish 타입으로 추론
} else {
pet.fly(); // Bird 타입으로 추론
}
}
_instanceof
: object의 프로토 타입 프로토타입 체인에 constructor.prototype이 존재하는지 판별합니다.
object: 판별할 객체
constructor: 판별 목표함수
object instanceof constructor
instanceof 연산자를 사용하면 객체가 특정 클래스의 인스턴스인지 확인할 수 있습니다.
class User {
name: string;
constructor(name: string) {
this.name = name;
}
}
const hello = new User('hello');
console.log(hello instanceof User); // true
instanceof를 통해 객체가 User인지 Staff인지 구분하고, 해당 속성에 안전하게 접근할 수 있습니다.
class User {
id = 100;
name = 'user';
}
class Staff {
staffId = 200;
name = 'staff';
}
function getId(arg: User | Staff) {
if (arg instanceof User) {
console.log(arg.id); // User 인스턴스면 id 출력
}
if (arg instanceof Staff) {
console.log(arg.staffId); // Staff 인스턴스면 staffId 출력
}
}
// 사용 예시
const user = new User();
const staff = new Staff();
getId(user); // 100
getId(staff); // 200
인데스 시그니처
: 객체의 키 이름을 아직 모르고 있고, 타입만 알고 있는 경우에 사용합니다.
interface UserType{
[index:string]: number | string; // 유니언 타입으로 사용하면 됩니다.
length:number;
name: string;// name에 string을 넣으면 [index:string]: number;와 충돌이 일어납니다.
}
const user:UserType = {
'name' : '서지발',
'age' :20 // 작음 따음표는 제거가 가능하지만 없는 키에도 접근가능한 단점이 있습니다.
}
* 어떤 타입이 올지 알수 있는 상황이라면, 인덱스 시그니처를 사용하기보다는 최대한 정확한 타입을 정의하는 것이 낫습니다.
인덱스 타입 쿼리 연산자 keyof
: 객체 타입의 키들을 리터럴 유니언 타입으로 추출하는 연산자입니다. 즉, 객체 타입의 모든 키 이름을 하나의 타입(유니언 타입)으로 만들어줍니다
type Point = {x:number; y:number;};
type p = keyof Point; // type P = 'x' | 'y';와 같습니다.
//인덱스 시그니처가 있을 때
type Arrayish = {[n:number]: unknown};
type A = leyof Arrayish; // type A = number;와 같습니다.
// 숫자 인덱스 시그니처가 있으면, keyof는 해당 인덱스 타입(number)을 반환합니다.
type Mapish = { [k: string]: boolean };
type M = keyof Mapish; // string | number;
//문자열 인덱스 시그니처가 있으면, 자바스크립트 객체 키가 항상 문자열로 변환되기 때문에 string | number가 됩니다
객체 리터럴에서 typeof와 함께 사용하겠습니다.
typeof로 객체의 타입을 추출하고, keyof로 키 유니언 타입을 만들 수 있습니다.
as const를 붙이면 모든 프로퍼티가 readonly 및 리터럴 타입으로 고정됩니다.
const DevelopStatus = {
ready: '준비중',
develop: '개발중',
complete: '개발완료',
} as const;
type StatusKey = keyof typeof DevelopStatus; // "ready" | "develop" | "complete"
let myStatus: StatusKey = 'ready';
매핑 타입
: 중복을 피하기 위해서 기존 정의된 타입을 새로운 타입으로 변환하는 문법입니다. 타입을 매핑 시키는 방법입니다.
제네릭 타입 T의 모든 프로퍼티 이름을 그대로 가져와서, 각 프로퍼티의 타입을 boolean으로 바꿔주는 타입입니다.만약 T가 { a: number; b: string }라면, OptionsFlags는 { a: boolean; b: boolean }이 됩니다.
type OptionsFlags<T> = {
[Property in keyof T]: boolean;
}
type Input = {
value: string;
onChange: () => void;
disabled: boolean;
}
type InputOptions = OptionsFlages<Input>
//type InputOptions = {
// value:boolean;
// onChange: boolean;
// disabled:booledn;
//}
readonly 수정자를 제거하여 모든 프로퍼티를 수정 가능하게 변환하는 유틸리티 타입입니다.
type CreateMutable<T> = {
-readonly [Property in keyof T[: t[Property];
}
조건부 타입
: 타입을 조건적으로 부여할 수 있습니다.
SomeType extends OtherType ? TureType : falseType;
Student 타입이 User 타입에 할당될 수 있다면 number이 되고 안되면 string이되도록 합니다.
interface User { name: string }
interface Student extends User { studentId: number }
type Example = Student extends User ? number : string // 결과: number
T에 number가 들어가면 IdLabel 할당되고 T에 string이 들어가면 NameLable이 할당됩니다.
interface IdLabel { id: number }
interface NameLabel { name: string }
type NameOrId<T extends number | string> = T extends number
? IdLabel
: NameLabel;
idOrName은 아직 타입이 안정해졌습니다(number또는 string타입) NameOrId은 들어온 타입에 따라 결정이 됩니다.
createLabel이 사용되는 곳에서 인자를 전달해줘야지 타입이 정해집니다.
function createLabel<T extends number | string>(idOrName: T): NameOrId<T> {
throw "uniplemented";
}
분산조건부 타입
: 제네릭 타입 위에서 조건부 타입은 유니언 타입을 만나면 분산적으로 작동합니다.
string | number와 같은 유니온 타입이 조건부 타입에 들어가면, 각각 분리되어 ToArray<string> → string[], ToArray<number> → number[]로 평가된 뒤 최종적으로 string[] | number[]로 결합됩니다.
type ToArray<t> = Textends any > T[] : never;
type StrArrOrNumArr = ToArray<string | number>
Test<T>에서 분산 조건부 타입이 동작해 number와 boolean을 개별 평가 → number는 조건 만족 → number, boolean은 불만족 → null → 최종 타입 number | null
type T = number | boolean;
type Test<T> = T extends number ? T : null;
type A = Test<T>; // 결과: number | null
lnfer 키워드
: extends 키워드와 함께 사용되며, 타입스크립트가 런타입에서 타입을 추론하게 됩니다.
T extends infer U ? X : Y
T가 length 프로퍼티를 가지면 해당 프로퍼티의 타입(U)을 추론해 반환하고, 없으면 never를 반환합니다. 예시에서는 { length: number }가 입력되어 number 타입이 결과로 나옵니다.
type LengthType<T> = T extends { length: infer U } ? U : never;
type A = LengthType<{ length: number }>; // 결과: number
type Afunc = (x:string, y:number) => void;
type b = GetParmType<BFunc>;
유틸리티 타입
: 타입을 쉽게 변환할 수 있습니다.
Partial<T>
: 모든 속성이 옵셔널로 변경된 타입을 반환합니다,
Partial<T>를 사용 전
interface SomeType {
a: string;
b: number;
}
Partial를 사용
type PartialType = Partial<SomeType>
Partial를 사용 후
type PartialType = {
a?: string | undefined;
b? number | undefined;
}
Readonly<T>
: 모든 속성을 Readonly로 변경된 타입을 반환합니다.
type ReadonlyUser = Readonly<User>; // { readonly name: string; readonly age: number }
Record<K,T>
: 속성의 키가 K이고, 속성의 값이 T인 타입을 반환합니다.
type Grades = Record<"math" | "eng", number>; // { math: number; eng: number }
Pick<T,K>
: 리터럴 타입으로 부분적인 프로퍼티들을 선택해 타입을 반환합니다.
type NameOnly = Pick<User, "name">; // { name: string }
Omit<T,K>
: 리터럴 타입으로 부분적인 프로퍼티들을 선택해 타입으로 반환합니다.
type WithoutAge = Omit<User, "age">; // { name: string }
Exclude<T,U>
: T타입에서 U타입을 제외시킨 타입을 반환합니다.
type T2 = Extract<"a" | "b" | 1, string>; // "a" | "b"
Extract<T,U>
: U에 할당 가능한 모든 유니온 멤버를 T에서 가져와서 반환합니다.
type T3 = NonNullable<string | null | undefined>; // string
NonNullable<T>
: T에서 null과 undefined를 제외하고 타입을 반환합니다.
type Fn = (a: number, b: string) => void;
type Params = Parameters<Fn>; // [number, string]
Parameters<T>
: 함수의 매개변수에서 사용된 타입을 튜플 타입으로 반환합니다.
type Fn = (a: number, b: string) => void;
type Params = Parameters<Fn>; // [number, string]
ReturnType<T>
: 함수의 리턴 타입을 반환합니다.
type Fn = () => number;
type Ret = ReturnType<Fn>; // number
Required<T>
: 모든 속성이 required로 변경된 타입을 반환합니다.
type User2 = { name?: string; age?: number };
type RequiredUser = Required<User2>; // { name: string; age: number }
'리액트' 카테고리의 다른 글
[React] useCallback, Meomoization (0) | 2025.04.29 |
---|---|
[React] Redux로 상태 관리하기 (1) | 2025.04.17 |
[React] 렌더링 최적화 (1) | 2025.04.16 |
[React] Reate Query와 Suspense (0) | 2025.04.15 |
[React] React Context API를 활용한 전역 상태 관리 (1) | 2025.04.14 |