함수를 선언할 때 매개변수와 반환 값에 타입을 작성
아무것도 반환하지 않을 경우에는 반환 값에 void
타입 작성
function sum(a: number, b: number): number {
return a + b;
}
선택적 매개변수
기본 매개변수
개인적으로 헷갈렸던 부분.. spread & rest 참고: spread와 rest
function sum(a: number, ...nums: number[]): number {
let total = 0;
for (let key in nums) {
total += nums[key];
}
return a + total;
}
보통 다음과 같은 범주에 대해 정의할 수 있다.
예시
// 인터페이스를 적용하지 않을 경우
let person = { name: 'YJ', age: 20 };
function logAge(obj: { age: number }) {
console.log(obj.age);
}
logAge(person);
// 인터페이스를 적용할 경우
interface personAge {
age: number;
}
// 인자를 더 명시적으로 표시할 수 있음
function logAge(obj: personAge) {
console.log(obj.age);
}
let person = { name: 'YJ', age: 20 };
logAge(person);
personAge
인터페이스는 age
1개의 속성만 갖지만 person
은 name
, age
총 2개의 속성을 가져도 상관 없다. 또한 여러 개의 속성일 경우 순서도 상관 없다. interface Student {
readonly studentId: number;
studentName: string;
age?: number;
gender: string;
courseCompleted: boolean;
// here
addComment(comment: string): string;
addComment: (comment: string) => string;
}
interface 인터페이스_이름 {
속성?: 타입;
}
readonly
를 붙인다.interface CraftBeer {
readonly brand: string;
}
let myBeer: CraftBeer = {
brand: 'Belgian Monk';
}
myBeer.brand = 'Korean Carpenter'; // error
ReadonlyArray<T>
타입을 사용한다.let arrr: ReadonlyArray<number> = [1, 2, 3];
arr.splice(0, 1); // error
arr.push(4); // error
interface login {
(username: string, password: string): boolean;
}
let loginUser: login;
loginUser = function(id: string, pw: string) {
console.log('로그인 했습니다');
return true;
}
interface CraftBeer {
beerName: string;
nameBeer(beer: string): void;
}
class myBeer implements CraftBeer {
beerName: string = 'Baby Guiness';
nameBeer(b: string) {
this.beerName = b;
}
constructor() {}
}
interface Person {
name: string;
}
interface Developer extends Person {
skill: string;
}
let fe = {} as Developer;
fe.name = 'josh';
fe.skill = 'TypeScript';
enum Direction {
Up, // 0
Down, // 1
Left = 5, // 5
Right // 6
}
enum Res {
No = 0,
Yes = 1
}
function respond(recipient: string, message: Res): void {
console.log(`recipient is ${recipient}, message is ${message}`);
}
respond('YJ', Res.Yes);
숫자형 이넘에만 존재
enum Enum {
A, B, C
}
let a = Enum.A; // 키로 값을 획득
let keyName = Enum[a]; // 값으로 키를 획득
console.log(`a: ${a} , keyName: ${keyName}`); // a: 0 , keyName: A
enum Direction {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT"
}
리터럴 타입
을 이용하면 좀 더 쉽게 작성할 수 있다.interface Location {
direction: "UP" | "DOWN" | "LEFT" | "RIGHT"
}
제한된 타입들을 동시에 지정하고 싶을 때 사용
|
연산자를 이용해서 타입을 여러 개 연결하는 방식
// text의 타입은 string이거나 number이다.
function logText(text: string | number) {
// ...
}
단순히 OR
라고 생각하는 건 주의해야 한다.
아래 예시에서 함수의 파라미터는 Person
이 될 수도, Developer
가 될 수도 있다. 하지만 타입스크립트의 입장에서는 introduce()
함수를 호출할 때 어느 타입이 올지 알 수 없다. 따라서 어느 타입이 오든 에러가 나지 않는 방식으로 추론하게 되기 때문에, 특정 타입에만 있는 속성을 사용하면 오류가 발생한다.
이러한 경우에 typeof
/in
/instanceof
등의 operator와 조건문을 사용해서 문제를 해결할 수 있다.
이와 같이 타입을 narrow down할 수 있게 해주는 것을 타입 가드라고 한다.
&
연산자를 이용해서 하나의 타입이 여러 타입을 모두 만족하도록 함interface Person {
name: string;
age: number;
}
interface Dev {
name: string;
skill: number;
}
type Capt = Person & Dev;
let capt: Capt = {
name: 'capt',
age: 20,
skill: 5,
}
function getText<T>(text: T): T {
return text;
}
getText<string>('hi');
getText('hi'); // 이렇게도 가능
getText<number>(10);
getText<boolean>(true);
any
를 사용한다면 함수가 동작은 하겠지만, 어떤 타입이 들어오고 어떤 타입이 반환되는지 알 수 없다. 이 문제를 해결할 수 있는 것이 제네릭이다.function logText<T>(text: Array<T>): Array<T> {
// text를 그냥 T 타입으로 하면 length 속성이 없다는 에러가 뜸.
// 이 때 Array<T>로 해서 제네릭에 타입을 줄 수 있음
console.log(text.length);
return text;
}
extends
를 통해 제약을 주는 방법interface LengthWise {
length: number;
}
function logText<T extends LengthWise>(text: T): T {
console.log(text.length);
return text;
}
logText('hi');
keyof
를 사용해서 객체의 속성을 제약하는 방법