일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 프로그래머스 데브코스 프론트엔드
- 이벤트 수식어
- vue 이벤트 수신
- nextjs사용법
- SCSS forward
- 고양이 사진 검색기
- vue mixin
- 다른컴퓨터에서 git사용
- 폼 입력 바인딩
- Spacer
- git 같은계정 다른 컴퓨터
- Vue
- 프로그래머스 데브코스
- SCSS extend
- 쌓임맥락
- intersection opserver
- 프로그래머스 K_Digital Training
- react next
- SCSS import
- vue 지역 컴포넌트
- postcss
- vuex map
- 리액트
- KDT 프로그래머스 데브코스 프론트엔드
- 리스트 렌더링
- netlify redirect
- flex
- SCSS use
- KDT 프로그래머스
- 프로그래머스 프론트엔드 데브코스
- Today
- Total
혼자 적어보는 노트
타입스크립트 프로그래밍 - 4장 본문
4장 함수
4장에서는 함수를 살펴보고 아래와 같은 내용을 다룬다.
- 함수를 선언하고 실행하는 방법
- 시그니처 오버로딩
- 다형적 함수
- 다형적 타입 별칭
# 특별한 상황을 제외하면 매개변수 타입은 추론하지 않는다.
- 문맥을 보고 타입을 추론하는 상황(문맥적 타입화)등 특별한 상황을 제외하면 매개변수 타입을 추론하지 않는다.
* 반환 타입은 자동으로 추론하기때문에 보통 실무에서는 반환타입을 명시하지 않고 추론하도록 한다.
# 함수에서 this를 사용할 때 첫번째 매개변수로 선언할 수 있다.
function fancyData(this: Date){
return ${this.getDate()}/${this.getMouth()}
}
fancyDate.call(new Date);
fancyDate() // 에러
함수 내부에서의 this가 의도한대로 동작할 수 있게 타입을 지정해둘 수 있다.
* this는 예약어이기때문에 다른 매개변수와 다르게 처리된다.
# 제너레이터로 반환시 반환 타입을 명시할 수 있다.
function* createNumbers(): IterableIterator<number> {
let n = 0;
while (1){
yield n++;
}
}
let numbers = createNumbers();
numbers.next() // {value: 0, done: false}
# 호출 시그니처
(a: number, b: number) => number
위와 같은 함수 타입 문법을 호출 시그니처(Call Signature) 또는 타입 시그니처(Type Signature)라고 한다.
* 여기서 a와 b는 문서화의 용도이기 때문에 타입과 할당에는 아무 영향을 주지 않음
* 함수 호출 시그니처는 바디를 포함하지 않아서 타입을 추론할 수 없기 때문에 반환 타입을 명시해야 함 (number)
# 오버로드된 함수
오버로드된 함수는 호출 시그니처가 여러개인 함수를 의미한다.
// 전체 시그니처
const type PersonMaker = {
(name: string, age: number): Person
}
보통 함수의 타입을 표현할 때 단축 시그니처를 사용하지만 함수 타입의 오버로딩을 할 때는
전체 시그니처를 사용하는 것이 좋다.
type PersonMaker = {
(name: string, age: number, gender: string): Person
(name: string, gender: string) : Person
}
const personMaker: PersonMaker = (
name: string,
ageOrGender: number | string,
gender?: string
) => {
}
이부분이 조금 헷갈렸는데 다시 읽으니 이해가 됐다.
personMaker에는 name, age, gender의 매개변수를 받을 수 있지만
상황에 따라 name과 gender만 들어올 수도 있다.
age가 없을 경우 2번째 매개변수는 age가 될 수도 있고 gender가 될 수도 있기 때문에 직접 선언해주어야 한다.
함수의 프로퍼티를 만드는데도 전체 시그니처를 사용할 수 있다.
const warnUser = (warning) => {
if(warnUser.wasCalled){
return;
}
warnUser.wasCalled = true;
alert(warning);
}
warnUser.wasCalled = false;
type WarnUser = {
(warning: string): void
wasCalled: boolean
}
WarnUser는 호출할 수 있는 함수임과 동시에 wasCalled를 가지고 있음을 나타낼 수 있다.
# 제네릭 타입 <T>의 위치
제네릭 타입은 선언 위치에 따라 타입의 범위와 제네릭 타입을 언제 구체 타입으로 한정하는지가 결정된다.
1. <T>를 호출 시그니처의 일부로 선언
type Filter = {
<T>(array: T[], f: (item: T) => boolean): T[]
}
const filter: Filter = (array, f) => {}
호출 시그니처의 여는 괄호 바로 앞에 선언하면 T의 범위를 개별 시그니처로 한정한다
(해당 타입의 함수를 실제로 호출할 때 타입을 T로 한정)
2. T의 범위를 타입 별칭으로 한정
type Filter<T> = {
(array: T[], f: (item: T) => boolean): T[]
}
// 위와 같이 선언할 경우
const filter: Filter<number> = (array, f) => {}
// 구체적인 타입 인수를 전달해주어야 한다.
T의 범위를 모든 시그니처로 한정한다.
type MyEvent<T> = {
target: T;
type: string;
};
let myEvent: MyEvent<HTMLElement | null> = {
target: document.querySelector('div'),
type: 'click',
};
위와 같은 제네릭 타입을 사용할 땐 타입이 자동으로 추론되지 않으므로
타입 매개변수를 명시적으로 한정해주어야 한다.
#T 타입을 가진 U (한정된 다형성)
type Person = {
name: string;
};
type Student = Person & {
class: string;
};
type OfficeWorker = Person & {
salary: number;
};
function updateName<T extends Person>(user: T, name: string): T {
return {
...user,
name,
};
}
T는 적어도 Person이어야 한다면 extends를 사용하여 타입을 제한할 수 있다. => name이 무조건 있어야 할 경우.
# 가변 인수의 개수 정의하기
const call = <T extends unknown[], R>(f: (...args: T) => R, ...args: T): R => {
//T는 어떤 타입의 배열
return f(...args);
};
function fill(length: number, value: string): string[] {
return Array.from({ length }, () => value);
}
call(fill, 10); // X 3개의 인수가 전달되어야 하는데 2개가 전달되어 에러
call(fill, 10, 'a'); // O
인수 배열 타입의 T와 임의의 가변값 R을 사용하여 가변인수의 개수를 정의할 수 있다.
# Promise 타입
promise는 제네릭 타입 매개변수를 명시하여 사용한다.
const promise = new Promise<number>(resolve =>
resolve(10);
);
promise.then(result => // number로 추론
result + 3;
)
여기서 제네릭 타입을 명시하지 않으면 result는 {}로 추론한다.
# 제네릭에 기본값을 추가할 수 있다.
기본 값을 정의해두면 사용할 때 타입 매개변수를 수동으로 작성하지 않아도 된다.
type MyEvent<T = HTMLElement> = {
target: T;
type: string;
};
let myEvent: MyEvent = { // 여기서 수동으로 작성하지 않아도 됨
target: document.querySelector('div'),
type: 'click',
};
# 기본타입을 가진 제네릭은 기본타입을 갖지 않는 제네릭의 뒤에 위치해야한다.
// X
type MyEvent<U extends HTMLElement = HTMLElement, T extends string> = {
// 에러 발생 : Required type parameters may not follow optional type parameters.
target: T;
type: U;
};
// O
type MyEvent<T extends string, U extends HTMLElement = HTMLElement> = {
target: T;
type: U;
};
'Typescript' 카테고리의 다른 글
[TypeScript] 객체의 key를 type으로 분리하기 (0) | 2022.08.01 |
---|---|
[TypeScript] String key로 객체에 접근하기 (0) | 2022.07.26 |
[Typescript] Type Guard로 타입 좁히기 (0) | 2022.07.13 |
[Typescript] React에서 Typescript 사용하기 (0) | 2022.05.24 |
[TypeScript] 제네릭(Generics) (0) | 2022.05.23 |