인프런 TIL : 타입스크립트 사용법 정리
기본 타입
Boolean
Number
String
Object | let arr: number{} = { ... };
Array | let arr: number[] = [1,2,3];
Tuple | 배열의 길이, 요소 고정
Enum | 상수의 집합
Any
Void | 반환값 없음
Null
Undefined
Never | while(true)와 같이 절대 만들어지지 않을 값의 타입
Unknown | any와 같이 모든 타입의 값이 할당될 수 있지만 엄격한 검사
enum
enum Answer {
Yes = 'Y',
No = 'N',
}
function askQuestion(answer: Answer) {
if (answer === Answer.Yes) {
console.log('정답입니다');
}
if (answer === Answer.No) {
console.log('오답입니다');
}
}
상수의 집합인 enum
은 object
와 비슷하지만 다음과 같은 차이점이 있다.
enum
은 string과 number만 허용 가능하다.- 선언 이후 값을 변경할 수 없다.
- 상수를 사용할 때보다 IDE의 적극적인 지원(단어추천)을 받을 수 있다.
unknown
- any를 제외한 다른 타입으로 선언된 변수에 할당될 수 없음
- 타입가드없이는 메소드 호출, 프로퍼티 접근, 인스턴스 생성이 불가능하다.
let variable: unknown
variable.foo.bar // Error: Object is of type 'unknown'.(2571)
variable[0] // Error
variable.trigger() // Error
variable() // Error
new variable() // Error
console.log(variable.length); // Error
if (typeof variable === "string") {
console.log(variable.length); // 가능
}
any vs unkown
any
는 타입을 좁혀서 사용하지 않아도 되지만, unknown
은 타입을 좁혀서 사용해야만 한다.
unknown
타입은 지정된 타입을 먼저 확인한 후에 무언가를 할 수 있으므로 unknown
을 사용하는 것이 보다 안전하다. 따라서 unknown
으로 any
를 대체하여 보다 안전한 코딩이 가능하다.
타입정의
함수 타입정의
function log(a: number, b: number, c?: number): number {
return a + b;
}
(a: number)
파라미터 타입정의function log ( ...): number
반환값 타입정의c?: string
옵셔널 파라미터
Interface 인터페이스
인터페이스 선언
interface User {
age: number;
name: string;
}
interface SumFunction {
(a: number, b: number): number;
}
인터페이스 적용
const seho: User = {
age: 23,
name: "세호"
}
function getUser(user: User) {
console.log(user);
}
getUser(seho);
extends 인터페이스 확장
interface Person {
name: string;
age: number;
}
interface Developer extends Person { // Person의 타입을 상속
language: string;
}
⬇⬇⬇⬇
interface Developer { // 위와 같은 의미
name: string;
age: number;
language: string;
}
interface Developer {
contact: number;
}
// 같은 interface 명으로 다시 만들 시 자동으로 확장됨
인터페이스를 통한 인덱싱, 딕셔너리 패턴
interface StringArray {
[index: number]: string; // 인덱스를 통해 지정하는 것은 string으로만 지정할 수 있다.
}
const iArr: StringArray = ['a', 'b', 'c'];
// iArr[0] = 10; // 불가능
iArr[0] = 'd';
// 딕셔너리 패턴
interface StringRegexDictionary {
[key: string]: RegExp // RegExp 정규표현식 타입으로만 지정해야 한다.
}
const iObj: StringRegexDictionary = {
// cssFile: 'css' //불가능
cssFile: /\.css$/,
jsFile: /\.js$/,
}
인터페이스 vs 타입
타입은 extends 확장이 불가능하며, 링크 클릭(ctrl+click) 불가능하다.
type으로 지정된 객체에 hover시 지정된 타입을 볼 수 있다.
▶ 확장성 등의 이유로 대체로 interface 선언을 추천하고 있다.
타입스크립트 operator
유니온, 인터섹션
interface Developer {
name: string;
skill: string;
}
interface Person {
name: string;
age: number;
}
function askSomeoneU(someone: Developer | Person) {
someone.name; // 공통된 타입만 사용 가능
}
var arr = [1, 2, 3, true, true, 'abc', 'hello']; // string | boolean | number
function askSomeoneI(someone: Developer & Person) {
someone.name; // 각각의 타입도 사용 가능
someone.name
}
function logMessage(value: string | number) {
if (typeof value === 'number') { // 타입가드
value.toString(); // 유니온타입으로 number 타입일 때의 단어추천 가능
}
if (typeof value === 'string') {
value.trim(); // string 타입일 때의 단어 추천
}
else throw new TypeError('value must be string or number');
}
타입스크립트의 class
클래스 생성
class PersonT {
constructor(age: number, name: string, contact: string) {
console.log('생성되었습니다');
this.name = name;
this.age = age;
this.contact = contact;
}
}
const sehoT = new PersonT(24, '세호', '010-2432-1214');
console.log(sehoT);
클래스 변수 접근 범위
class PersonT {
public age: number; // 변수 접근 범위: 모든 클래스
protected name: string; // 변수 접근 범위: 해당 클래스와 자식 클래스
private contact: string; // 변수 접근 범위: 해당 클래스
readonly log: string; // 변수 접근 범위: 변경불가, 읽기만 가능
}
generic
function logText<T>(text: T): T { // 받는타입: T 인자타입: T 반환타입: T
console.log(text);
return text;
}
logText<number>(23);
제네릭의 타입제한
function logText<T>(text: T): T { // 받는타입: T 인자타입: T 반환타입: T
console.log(text);
return text;
}
logText<number>(23);
다음 상황에서 타입스크립트는 아직 talking이 string인지 모르기 때문에 error가 발생한다.
const talking = logText<string>('abc'); talking.split('');
아래는 위와 같은 상황을 해결하기 위한 타입제한 방법이다.
제네릭의 타입제한 - 1. 힌트주기
function logTextLength<T>(text: T[]): T[] { // text에 힌트를 주는 식
console.log(text.length);
text.forEach(function (text) {
console.log(text)
})
return text;
}
logTextLength<string>(['hi', 'abc']);
제네릭의 타입제한 - 2.정의된 타입 이용
interface LegnthType {
length: number;
}
function logTextLength<T extends LegnthType>(text: T): T {
text.length;
console.log(text.length);
return text;
}
logTextLength('abc');
logTextLength({length: 10});
제네릭의 타입제한 3 - keyof
interface ShoppingItem {
name: string;
price: number;
stock: number;
}
// ShoppingItem의 옵션 중 하나가 제네릭이 된다는 정의
function getShoppingItemOption<T extends keyof ShoppingItem>(itemOption: T): T {
return itemOption
}
getShoppingItemOption(10);
getShoppingItemOption<string>('a');
getShoppingItemOption("name")
타입단언 assertion
var c;
c = 20;
c = 'c';
var d = c as string // string으로 타입지정, as 사용 안할 시 any타입으로 설정됨
타입스크립트 추론이 아닌, 개발자가 직접 타입을 지정하는 방법
타입단언 예시 - DOM API 조작
var div = document.querySelector('div');
div.innerText; // error
위와 같이 DOM API를 조작하는 상황에서 div
가 null
일 수 있기 때문에 if (div)
를 통해 제한을 두어야 한다.
이때 var div = document.querySelector('div') as HTMLDivElement;
타입단언으로 null의 가능성을 없애면 바로 접근할 수 있다.
타입단언 예시 - 인수가 필요하지 않은 상황에서의 에러 대처
또한 위처럼 인수가 필요하지 않음에도 에러가 날 수 있는데, ({} as ...)와 같이 임시로 에러를 없앨 수 있다.
is타입을 이용한 타입가드 패턴
interface Developer {
name: string;
skill: string;
}
interface Person {
name: string;
age: number;
}
function isDeveloper(target: Developer | Person): target is Developer
return (target as Developer).skill !== undefined; // Developer면 true 반환
}
if (isDeveloper(tony)) { // 타입가드를 이용한 패턴
console.log(tony.skill);
} else {
console.log(tony.age);
}
if (isDeveloper(tony))
: target is Developer
에서 target
이 Developer
면 true
를 반환하도록 하는 패턴
인터페이스 확장
interface User {
id: number;
name: string;
age: number;
address: string;
createdAt?: string;
updatedAt?: string;
}
Partial
interface User {
id: number;
name: string;
age: number;
address: string;
createdAt?: string;
updatedAt?: string;
}
Partial: Optional 설정, 모든 필드가 있어도 되고 없어도 됨.
위와 같은 상황에서 다음과 같이 사용가능 const parial: Partial<User> = { createdAt: "2", };
Required
Required: 모든 필드 Required
, 모든 필드가 있어야만 한다.
위와 같은 상황에서 다음처럼 모든 필드를 기입해야만 사용 가능하다.
const required: Required<User> = {
id: 1,
name: "Lee",
age: 0,
address: "Seoul",
createdAt: "필수",
updatedAt: "필수",
};
Pick, Omit
Pick: 특정 필드만 사용
const pick: Pick<User, "name" | "age"> = { name: "", age: 3, };
Omit: 특정 필드만 제외하고 사용
const omit: Omit<User, "id" | "createdAt"> = { name: "", age: 3, address: "", };
Mixed
const mixed: Omit<User, "id" | "age" | "address"> & Pick<Partial<User>, "age"> =
{
name: "",
age: 3,
};
Mixed: Interface 여러개 동시 사용
extends
interface Time {
hour: number;
minute: number;
}
interface DateTime extends Time {
month: number;
day: number;
}
interface TimeFormat extends Pick<Time, 'hour'> {
ampm: number;
}
extends: 인터페이스 상속
Mapped Type
map()을 타입에 적용한 것과 같은 효과
type HeroProfiles = { [K in Heroes]: number };
const heroInfo: HeroProfiles = {
Hulk: 54,
Thor: 1000,
Capt: 33,
}
⬇⬇⬇⬇
type HeroProfiles = {
Hulk: number;
Thor: number;
Capt: number;
}
keyof를 이용한 Mapped Type
type Subset<T> = {
[K in keyof T]?: T[K];
}
참고사이트: 삼바의 성장 블로그, 타입스크립트 핸드북
Author And Source
이 문제에 관하여(인프런 TIL : 타입스크립트 사용법 정리), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@te-ing/인프런-TIL-타입스크립트-사용법-정리저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)