Search
Duplicate
📒

노트 템플릿 시리즈

수업
JavaScript/TypeScript
주제
5 more properties
참고

TS 인터페이스

NOTE
타입스크립트의 인터페이스는 타입의 ‘틀’로서 사용할 수 있다.

목차

NOTE

1. 목차

NOTE

목차

NOTE
타입스크립트의 인터페이스는 타입의 ‘틀’로서 사용할 수 있다.
// 인터페이스명은 대문자로 짓는다 interface Human { name: string; // name 키는 문자열 타입 age: number; // age 키는 넘버 타입 boo(): void; // boo 함수는 void 타입 } // 인터페이스 자체를 타입으로 줘서 객체 생성 const person: Human = { name: "da", age: 5, boo: () => console.log("this is boo"), }; // 매개변수에서 인터페이스를 타입으로 받는다. function booboo(a: Human): void { console.log(`${a.name} is ${a.age} years old`); }; booboo(person); // da is 5 years old person.boo(); // this is boo
TypeScript
복사

선택적 프로퍼티 ( ?:)

선택적 프로퍼티를 사용하면 값이 없을 수 있다. 사실 Union타입으로 number | undefined 선언과 동일하다.
// 둘이 표현하고자 하는 타입 구조는 같다. interface IUser { name: string; age?: number; } interface TUser = { name: string; age: number | undefiened; }
TypeScript
복사

읽기 전용 프로퍼티(readOnly)

읽기 전용 속성은 단어 그대로, 인터페이스로 객체를 처음 생성할 때만 값을 할당하고 그 이후에는 변경할 수 없는 속성을 의미한다.
interface User{ name: string; age: number gender?: string readonly birthYear: number } let user: User = { name: 'jeff', age: 30, birthYear: 2010 }
TypeScript
복사
[readonly vs const]
readonly와 const 는 처음 초기화 할때만 값을 선언하고, 그후에는 값을 수정하지 못한다는 점에서 유사하다. 다만 이 둘은 사용처가 다른데, 변수는 const를 쓰고 프로퍼티는 readonly를 사용된다는 점만 기억하면 된다.
만약 모든 속성이 readonly일 경우, 일일히 프로퍼티마다 readonly를 찍어주지말고, 따로 유틸리티나 단언 타입을 활용하자.
interface IUser { name: string; age: number } let user2 : Readonly<IUser> = { name: 'Neo', age: 36 } // user2.age = 85; // user2.name = 'Evan'
TypeScript
복사

인터페이스 호환 / 확장

같은 이름의 인터페이스 여러 개를 만들 수 도 있다. 이들은 중복이 안되면, 안의 선언된 프로퍼티가 하나로 합쳐진다. 또한 extends를 사용하면 확장을 구현할 수 있다.
interface IFullName { firstName: string, lastName: string } interface IFullName { middleName: string } // 호환(동일 인터페이스가 합쳐짐) const fullName: IFullName = { firstName: 'Tomas', middleName: 'Sean', lastName: 'Connery' };
TypeScript
복사
interface Person { name: string; } interface Developer extends Person { skill: string; } // 확장 let fe: Developer = { name: 'josh', skill: 'TypeScript' };
TypeScript
복사

인터페이스 함수 타입

인터페이스는 함수의 모양을 정의할 수 있으며, 이를 전문 용어로 호출 시그니처라 부를 수 있다.
인터페이스로 함수 자체 타입을 정의할 때 다음과 같이 함수 속성 값도 정의할 수 있다.
interface GetText { (name: string, age: number): string; // 함수 totalCall?: number // 변수? } const getText: GetText = (name, age) { if(getText.totalCall !== undefined){ getText.totalCall += 1; console.log(`totalCall: ${getText.totalCall}`) } return ''; } getText.totalCall = 0; getText('', 0); getText('', 0);
TypeScript
복사
호출 시그니처는, 자바스크립트 객체의 prototype에 메소드를 추가적으로 등록할때도 유용히 사용된다.
다음은 자바스크립트의 기본 객체인 Object에 getshortKeys()라는 새로운 메서드를 프로토타입으로 등록한다.
interface Object { getShortKeys(this: object): string[] } Object.prototype.getShortKeys = function () { return Object.keys(this).filter((key) => key.length <= 3); }; const obj = { a: 1, bb: 2, ccc: 3, dddd: 4 } console.log(obj.getShortKeys())
TypeScript
복사

인덱스 타입

규칙이 있는 속성이라면, 변수라는 곳에 값을 넣어 유기적으로 이용하듯이, 인터페이스도 이를 활용할 수 있다.
type Score = 'A' | 'B' | 'C' | 'D' | 'F'; interface User { name: string; [grade: number]: Score; // indexable 타입 (선택적 프로퍼티 처럼 반드시 선언 안해줘도 된다.) } const user1: User = { name: '홍길동', 1: 'A', }; const user2: User = { name: '임꺾정', 3: 'F', }; const user3: User = { name: '박혁거세', 2: 'B', };
TypeScript
복사
interface IItem { [itemIndex: number]: string // Index signature } let item: IItem = ['a', 'b', 'c']; // Indexable type console.log(item[0]); console.log(item[1]); console.log(item['0']); // Error - itemIndex 인덱서블 속성은 number 타입이라 에러
TypeScript
복사

타입 추론

개발자가 굳이 변수 타입을 선언하지 않더라도 컴파일이 스스로 판단해서 타입을 넣어준다.
function add(x: number, y: number) { return x + y }; // 리턴 타입 명시 X const result = add(1, 2); // 리턴 타입을 명시 안해줘도 어차피 number타입끼리의 연산은 number일테니 tsc가 이정도의 추론은 알아서 해준다.
TypeScript
복사
기본적인 타입에 대해서는 컴파일러가 잘 추론해주지만, 가끔 이상하게 하는 경우가 있다.
const obj = { red: 'apple', yellow: 'banana', green: 'cucumber', }; const obj = { red: string, yellow: string, green: string, };
TypeScript
복사
각 타입이 상수가 아닌 string으로 컴파일러는 인식한다.

타입 단언

타입 단언이란 이 타입은 특정 타입이라고 컴파일러에게 단언하는 것이다.
즉 컴파일러가 추론하지 않고, 직접 지시해서 타입을 줄 수 있다.
console.log(obj.getShortKeys()) let assertion: unknown = "타입 어셜선 단언" let assertions_count: number = (assertion as string).length
TypeScript
복사
타입스크립트의 느낌표 연산자를 사용해서 non-null을 보장할수도 있다.
const div = document.querySelector("div")! div!.innerHTML = "asdf"
TypeScript
복사

타입 가드

타입 가드는 에러를 줄일 수 있는 방어 코드 기법을 의미한다.
타입 가드는 어떠한 전용 문법이 있는 것이 아니라, 타입 스크립트에서 우리가 흔히 쓰는 if문 조차도 분기를 잘해서 오류를 최소화할 수 있다면 그것이 바로 타입 가드 기법이 될 수 있다.
대표적인 타입 가드에는 다음과 같은 방법이 있다.
1.
typeof: 일반 타입 체크
2.
Array.isArray() : 배열 체크
3.
.type / in : 객체 속성 체크
일반 타입 체크
function numOrStr(a: number | string){ if(typeof a === 'string'){ a.split(',') } if(typeof a === 'number'){ a.toFixed(1); } }
TypeScript
복사
function numOrNumArr(a: number | number[]){ if(Array.isArray(a)){ a.slice(1); } else{ a.toFixed(1); } }
TypeScript
복사
type Lion = { gender: 'F' | 'M', bite: boolean } type Ant = { gender: 'F' | 'M', acid: boolean } type Sparrow = { gender: 'F' | 'M', fly: boolean } function typeCheck(a: Lion | Ant | Sparrow){ if('bite' in a){ a.bite = true } else if('acid' in a){ a.acid = true; } else { a.fly = true } }
TypeScript
복사
in 연산자 ⇒ 객체의 key값을 꺼내오는 기능이며, 특정 key값의 여부에 따라 동작하도록 설정한다.
null 타입가드
function sample(data: number[] | null) { // 가장 먼저 data 가 null 인지 검사한다. // JavaScript 에서 `typeof null == 'object'` 의 결과가 true 이기 때문에, null 여부를 판별할 수 없기 때문이다. // 따라서 if 조건문에 data 가 유효한 값인지 판단하는 로직을 넣는다 if (data && typeof data === 'object') { for (const number of data) { console.log(number); } } }
TypeScript
복사
for … of 문의 경우 반복가능한 객체의 요소를 반복하는데 사용된다.

제네릭

제네릭이란 타입을 변수화한것이다.
function add<T>(x: T, y: T): T { return x + y; } add<number>(1, 2);
TypeScript
복사
// 제네릭 인터페이스 interface Mobile<T> { name: string; price: number; option: T; // 제네릭 타입 - option 속성에는 다양한 데이터 자료가 들어온다고 가정 } // 제네릭 자체에 리터럴 객테 타입도 할당 할 수 있다. const m1: Mobile<{ color: string; coupon: boolean }> = { name: 's21', price: 1000, option: { color: 'read', coupon: false }, // 제네릭 타입의 의해서 option 속성이 유연하게 타입이 할당됨 }; const m2: Mobile<string> = { name: 's20', price: 900, option: 'good', // 제네릭 타입의 의해서 option 속성이 유연하게 타입이 할당됨 };
TypeScript
복사
type numOrStr = number | string; // 제네릭에 적용될 타입에 number | string 만 허용 function identity<T extends numOrStr>(p1: T): T { return p1; } identity(1); identity('a'); // identity(true); //! ERROR // identity([]); //! ERROR // identity({}); //! ERROR
TypeScript
복사

객체 타입변환

typeof 연산자

객체 데이터 → 객체 타입 변환 연산자
const obj = { red: 'apple', yellow: 'banana', green: 'cucumber', }; // 위의 객체를 타입으로 변환하여 사용하고 싶을때 type Fruit = typeof obj; /* type Fruit = { red: string; yellow: string; green: string; } */ let obj2: Fruit = { red: 'pepper', yellow: 'orange', green: 'pinnut', };
TypeScript
복사

keyOf 연산자

객체 형태의 타입을 따로 속성만 뽑아서 유니온 타입으로 만들어준다.
type Type = { name: string; age: number; married: boolean; } type Union = keyof Type; // type Union = name | age | married const a:Union = 'name'; const b:Union = 'age'; const c:Union = 'married';
TypeScript
복사
const obj = { red: 'apple', yellow: 'banana', green: 'cucumber' } as const; type Key = typeof obj[keyof typeof obj]; // 객체의 value들만 가져와 상수 타입으로 let ob2: Key = 'apple'; let ob3: Key = 'banana'; let ob4: Key = 'cucumber';
TypeScript
복사

맵드 타입

mapped type이란 기존에 정의되어 있던 타입을 새로운 타입으로 변환해주는 문법을 의미한다.
인터페이스에 있는 모든 속성을 루프문 같이 순회해서 optionl(?)로 변경하거나 readonly로 지정한다.
interface Obj { prop1: string; prop2: string; } type ChangeType<T> = { [K in keyof T]: number; }; type Result = ChangeType<Obj>; /* { prop1: number; prop2: number; } */
TypeScript
복사

타입스크립트 - 유틸리티 타입

Partial<T>

TYPE의 모든 속성을 선택적으로 변경한 새로운 타입을 반환한다.
interface User { name: string; age: number; phone: number; } type Partial_User = Partial<User> // 인터페이스 User의 속성을 모두 optional 설정 /* type Partial_User = { name?: string | undefined; age?: number | undefined; phone?: number | undefined; } */ const user: Partial<User> = { name: 'B', };
TypeScript
복사

Required<T>

TYPE의 모든 속성을 옵셔널에서 필수로 변경한 새로운 타입을 반환한다.
interface User { name?: string; age?: number; phone: number; } type Required_User = Required<User>; // 인터페이스 User의 속성을 모두 일반 타입으로 /* type Required_User = { name: string; age: number; phone: number; } */ const user: Required<User> = { name: '홍길동', age: 22, phone: 111, };
TypeScript
복사

ReadOnly<T>

Type의 모든 속성을 읽기전용으로 변경한다.
interface User { name?: string; age?: number; phone: number; } type Readonly_User = Readonly<User>; // 인터페이스 User의 속성을 모두 readonly 설정 /* type Required_User = { readonly name?: string | undefined; readonly age?: number | undefined; readonly phone: number; } */ const user: Readonly<User> = { name: '홍길동', age: 22, phone: 111, }; user.age = 11; // ERROR !!
TypeScript
복사

Record<Key, Type>

제네릭의 Key를 속성으로, 제네릭의 Type을 속성값의 타입으로 지정하는 새로운 타입을 반환합니다.
interface User { name?: string; age?: number; phone: number; } type Readonly_User = Readonly<User>; // 인터페이스 User의 속성을 모두 readonly 설정 /* type Required_User = { readonly name?: string | undefined; readonly age?: number | undefined; readonly phone: number; } */ const user: Readonly<User> = { name: '홍길동', age: 22, phone: 111, }; user.age = 11; // ERROR !!
TypeScript
복사

ReadOnly<T>

Type의 모든 속성을 읽기전용으로 변경한다.
interface User { name?: string; age?: number; phone: number; } type Readonly_User = Readonly<User>; // 인터페이스 User의 속성을 모두 readonly 설정 /* type Required_User = { readonly name?: string | undefined; readonly age?: number | undefined; readonly phone: number; } */ const user: Readonly<User> = { name: '홍길동', age: 22, phone: 111, }; user.age = 11; // ERROR !!
TypeScript
복사