유튜브 '코딩앙마'님의 TS강의를 보며 잊어버릴 것같은 것들만 정리해보자.
//배열을 선언할 시 가능한 두가지 방법
let a:number[] = [1,2,3];
let a:Array<number> = [1,2,3];
//튜플
let b: [string, nuumber];
b = ['z', 1];
//b = [1, 'z']; // 순서도 엄격히 맞춰줘야 한다.
//함수가 아무것도 반환하지 않을 때 사용하는 void.
function saYhello():void{
console.log('HELLO!');
}
//never
function showError():never{
throw new Error();
} // 에러를 반환하거나,
function infLoop():never{
while(true) {
//do something..
}
} //영원히 끝나지않는 함수.
//enum
enum Os {
window,
Ios,
Android
}
enum에 값을 할당하지 않으면, 자동으로 0부터 할당된다.
//enum
enum Os {
window = 3, // 그 다음 값들은 4, 5가 된다.
Ios, //10을 할당한다면 다음 값은 11이 된다.
Android
}
이렇게 양방향으로 인식된다.
이런식으로 사용할 수 있다.
문자열도 할당할 수 있으며, 이 때는 단방향으로 인식된다.
컴파일 시에 const Os = {}의 형식으로 컴파일된다!
enum Os {
Window = 'win',
Ios = 'ios',
Android = 'and'
}
let myOs:Os; //Os에 있는 값들만 사용가능하다.
이런 식으로 사용가능.
특정값만 입력할 수 있도록 강조하고 싶을 때, 그리고 그 값들이 공통점이 있을 때 enum을 사용한다.
let user:object;
user = {
name: 'xx',
age: 30
}
이런식으로 덜렁 object만 써주면 에러발생한다.
프로퍼티를 정의해서 객체로 사용하고자 할때는 인터페이스를 사용한다.
interface 내부에 gender추가해도 소용없다.
user객체 내부에 gender가 사용되지않고 있기 때문.
?를 사용한다.
//readonly와 grade부분을 보자.
interface User {
name : string;
age : number;
gender?: string;
readonly birthYear : number;
[grade:number] : string; // 키를 number로, 값을 string으로 받을 수 있는 프로퍼티를 여러개 추가할 수 있다.
}
let user : User = {
name: 'xx',
age: 30,
birthYear : 2000,
1 : 'A',
2 : 'B'
}
user.age = 10; //
user.gender = 'male';
user.birthYear = 1999; //readonly로 선언됐기 때문에 할당 후 수정불가.
grade부분은 더 좋은 방법이 있다.
type score = 'A' | 'B' | 'C' | 'F';
interface User {
name : string;
age : number;
gender?: string;
readonly birthYear : number;
[grade:number] : score; //type에서 지정한 값들 이외에는 올 수가 없다!
}
let user : User = {
name: 'xx',
age: 30,
birthYear : 2000,
1 : 'A',
2 : 'B'
}
interface의 사용예를 더 보고 가자.
interface로 class를 지정해보자.
확장(extends)을 사용해보자.
//확장 시 여러 인터페이스를 동시에 적용 가능.
interface Car {
color: string;
wheels: number;
start(): void;
}
interface Toy {
name: string;
}
interface ToyCar extends Car, Toy {
price : number;
}
선택적 매개변수를 앞에서 사용하면 안된다.
굳이 사용하고 싶다면
이렇게 명시적으로 사용해야 한다.
//나머지 매개변수에 대한 형식지정.
function add(...nums: number[]) {
return nums.reduce((result, num) => result + num, 0);
}
add(1, 2, 3)
//literal
const userName1 = 'Bob';
let userName2: string | number = 'Tom';
userName2 = 3;
type Job = 'police' | 'developer' | 'teacher';
interface User {
name : string;
job : Job;
}
const user: User = {
name: 'Bob',
job: 'developer',
};
interface HighSchoolStudent {
name: number | string;
grade: 1 | 2 | 3;
}
//Union types
interface Car {
name: 'car';
color: string;
start(): void;
}
interface Mobile {
name: 'mobile';
color: string;
call(): void;
}
function getGift(gift: Car | Mobile) {
console.log(gift.color);
if(gift.name === 'car'){
gift.start(); // Car에만 start()가 있기 때문.
} else {
gift.call();
}
}
//Intersection Types
interface Car {
name: string;
start(): void;
}
interface Toy {
name: string;
color: string;
price: number;
}
const toyCar: Toy & Car = { //모든 프로퍼티를 사용해야 한다.
name: '타요',
start() {},
color: 'blue',
price: 1000,
}
class Car {
color: string;
constructor(color: string){
this.color = color;
}
start() {
console.log('start');
}
}
const bmw = new Car('red');
//멤버변수를 사용하지 않는 방법.
class Car {
//color: string;
constructor(public color: string){ //public 또는 readonly도 가능!
this.color = color;
}
start() {
console.log('start');
}
}
const bmw = new Car('red');
//접근 제한자(Access modifier) - public, private, protected
class Car {
name: string = 'Car';
color: string;
constructor(color: string){
this.color = color;
}
start() {
console.log('start');
}
}
class Bmw extends Car {
constructor(color: string) {
super(color);
}
showName() {
console.log(super.name);
}
}
const z4 = new Bmw('black');
위의 스샷에서 헷갈릴까봐 적어두는데 첫번째 주석에서 public이 아니라 private일때만 Car안에서만 접근가능이라는 뜻이다.
그리고 public은 생략하고 사용 가능이다.
protected는 자식클래스에는 존재할 수 있으나 인스턴스로는 존재할 수없다!
public - 자식클래스, 클래스 인스턴스 모두 접근 가능
protected - 자식 클래스에서만 접근 가능
private - 해당 클래스 내부에서만 접근 가능
class 내 객체 생성시마다 함께 생성되는 멤버 변수(메서드 밖에서 선언된 변수)를
static 화 하여 생성시마다 생기는 메모리 누수를 막아보자
// keyof
interface User {
id: number;
name: string;
age: number;
gender: 'm' | 'f';
}
type UserKey = keyof User; // 'id' | 'name' | 'age' | 'gender'
const uk:UserKey = 'id' // User 인터페이스의 키값을 입력하면 된다.
// Partial<T>
interface User {
id: number;
name: string;
age: number;
gender: 'm' | 'f';
}
let admin: Partial<User> = { //partial의 사용방법.
id: 1,
name: 'Bob',
}
// interface User {. //Partial을 쓰면 이것과 같은 형태이다.
// id?: number;
// name?: string;
// age?: number;
// gender?: 'm' | 'f';
// }
// Required<T>
interface User {
id: number;
name: string;
age?: number;
}
let admin: Required<User> = { //age가 필수 프로퍼티가 되어버렸다. 안넣으면 에러.
id: 1,
name: 'Bob',
age: 30,
}
// Readonly<T>
interface User {
id: number;
name: string;
age?: number;
}
let admin: Readonly<User> = {
id: 1,
name: 'Bob',
}
admin.id = 4; //Readonly로 감싸준다면 값 못바꾼다. (원래 가능.)
// Record<K,T> 예제 1.
// interface Score {
// '1': 'A' | 'B' | 'C' | 'D';
// '2': 'A' | 'B' | 'C' | 'D';
// '3': 'A' | 'B' | 'C' | 'D';
// '4': 'A' | 'B' | 'C' | 'D';
// }
const score: Record<'1'|'2'|'3'|'4', 'A' | 'B' | 'C' | 'D'> = { //Record<key, value>
1: 'A',
2: 'C',
3: 'B',
4: 'D',
}
type Grade = '1'|'2'|'3'|'4';
type Score = 'A' | 'B' | 'C' | 'D'; //type으로 저장 후 사용 가능.
const score: Record<Grade, Score> = {
1: 'A',
2: 'C',
3: 'B',
4: 'D',
}
// Record<K,T> 예제 2.
interface User {
id: number;
name: string;
age: number;
}
function isValid(user:User){
const result: Record<keyof User, boolean> = { //keyof를 활용하여 키값을 입력했다.
id: user.id > 0,
name : user.name !== '',
age : user.age > 0
}
return result;
}
// Pick<T, K>
interface User {
id: number;
name: string;
age: number;
gender: 'M' | 'F';
}
const admin: Pick<User, 'id' | 'name'> = { //id와 name만 가지고 왔다.
id: 0,
name: 'Bob',
}
// Omit<T,K>
interface User {
id: number;
name: string;
age: number;
gender: 'M' | 'F';
}
const admin: Omit<User, 'age' | 'gender'> = { // 특정 프로퍼티 값 제외.
id: 0,
name: 'Bob',
}
// Exclude<T1, T2>
type T1 = string | number | boolean;
type T2 = Exclude<T1, number | string>; //boolean만 남는다.
// NonNullable<Type>
//null과 undefined를 제외한다.
type T1 = string | null | undefined | void;
type T2 = NonNullable<T1> // string과 void만 남는다.