TS 상속
인터페이스는 키워드를 통해 클래스가 따라야 하는 유형을 정의하는데 사용
인터페이스: 복합적 구조를 나타내기 위해 사용된다.
// 인터페이스 이름: Shape
// 인터페이스: 복합적 데이터 단위, 이름만으로 가치가 있다.
// 인터페이스를 잘 만들어야 좋다
// return 타입이 number이다.
interface Shape {
// getArea의 파라미터는 없고 return 타입은 number
getArea: () => number;
}
// interface의 상속(구현은) implements이다.
// Rectangle클래스가 두개 이상의 인터페이스(Shape, A) 구현방법
class Rectangle implements Shape {
public constructor(protected readonly width: number, protected readonly height: number) {}
public getArea(): number {
return this.width * this.height;
}
}
상속은 존재하는걸 받는 것을 의미한다.
타입(규격) 즉 interface안에는 비어있다 그것을 받는 것을 구현이라고 한다.
TS 상속 확장
interface Shape{
// getArea의 파라미터는 없고 return 타입은 number
getArea:()=> number;
}
// Rectangle클래스가 두개 이상의 인터페이스(Shape, A) 구현방법
class Rectangle implements Shape, A {
public constructor(protected readonly width: number, protected readonly height: number) {}
public getArea(): number {
return this.width * this.height;
}
}
// Square는 하나의 인자 필요
class Square extends Rectangle {
public constructor (width: number) {
super(width, width);
// super 상위에 전달하는 방법
// 반드시 super를 포함해야한다. 안그러면 컴파일에러 발생생
}
}
const myReact = new Rectangle(10, 20);
console.log(myReact.getArea());
밑에 하위 클래스로 extends가 있다.
extends 뒤에 나오는건 class이다. 즉 extends rectangle은 class이다.
squrare -> Rectangle ....> shpae
...> A
super 생성자는 public의 constructor를 의미
interfaces는 객체 생성 불가, 타입을 지원하는 규격이다.
추상적이다.
즉, 구현되어 있지 않고 비어있다.
interfaces들의 생성은 implemets가 아닌 extends를 사용해야한다.
타입을 확장시키는것도 중요하다.
생성을 한다? 메모리에 올라간다. <- 인터페이스는 x
override
super의 메서드를 sub class에서 내용을 달리해서 채우는 것
내용을 달리한다? override를 의미
왜 쓰냐? 실수방지하기위해
interface Shape{
// getArea의 파라미터는 없고 return 타입은 number
getArea:()=> number;
}
// Rectangle클래스가 두개 이상의 인터페이스(Shape, A) 구현방법
class Rectangle implements Shape, A {
public constructor(protected readonly width: number, protected readonly height: number) {}
public getArea(): number { // 구현현
return this.width * this.height;
}
public toString(): string {
return `Rectangle[width=${this.width}, height=${this.height}]`;
}
}
// Square는 하나의 인자 필요
class Square extends Rectangle {
public constructor (width: number) {
super(width, width);
// super 상위에 전달하는 방법
// 반드시 super를 포함해야한다. 안그러면 컴파일에러 발생생
}
public override toString(): string {
return `Square[width=${this.width}]`;
}
}
const myReact = new Rectangle(10, 20);
console.log(myReact.getArea());
console.log(myReact.toString());
추상 클래스
(<-> 구체적이다.)
메모리에 못 올라가 객체화할 수 없다.
내용은 { } 여기 안에 있어야한다.
abstract class Polygon {
// number는 호출도 아니다 왜? 뒤에 소괄호가 없기에
public abstract getArea(): number;
// 추상적이기에 abstract를 작성
public toString(): string {
return `Polygon[area=${this.getArea()}]`;
}
}
class Rectangle extends Polygon {
public constructor(protected readonly width: number, protected readonly height: number) {
super();
}
// 그러나 여기서 getArea()에서는 구현하도록 강제한다. { }
// 위에서 추상적으로 적으면 밑에서 구현해야한다.
public getArea(): number {
return this.width * this.height;
}
}
추상적으로 작성하면 어디에 유용하냐?
점점 super 가 될 수록 (상속의 관계가 높아지다 보면) 구체적이지 못한다.
양세현 -> 사람 -> 동물
walk() {,,,} -> abstact walk(); -> 구체적 x
만일 사람이 여러명인 클래스를 만든다고 치면
마재형 () {,,,} - , 홍길동 () {,,,} - , 전은숙 () {,,,} 은 각각의 walk하는 기능이 있다.
사람을 상속하면 무조건 walk가 있어야 한다. (강제로 한다.)
동물을 호출하면 문제가 된다. 왜냐하면 walk가 없기에
프로그램의 의도는 굉장히 중요하다.
TS 기본 제네릭
유연하다.
function createPair<S, T>(v1: S, v2: T): [S, T] {
return [v1, v2]; // 형태가 고정된 타입을 튜플이라고한다. 즉, 여기서는 튜플을 리턴
}
console.log(createPair<string, number>('hello', 42)); // ['hello', 42]
class NamedValue<T> {
// _value를 선언하고 싶은데 지금 고정하는게 아니다.
private _value: T | undefined;
constructor(private name: string) {}
public setValue(value: T) {
this._value = value;
}
public getValue(): T | undefined {
return this._value;
}
public toString(): string {
return `${this.name}: ${this._value}`;
}
}
// 객체를 생성할때 밑에 타입을 선언하면 된다.
let value = new NamedValue<number>('myNumber');
value.setValue(10);
console.log(value.toString()); // myNumber: 10
개발의 의도를 살려서 개발하는게 타입스크립트의 목표이다.
💭 아 배고프다
유형 별칭
유형 별칭의 제네릭을 사용하면 재사용이 더 높은 유혀으로 만들 수 있다.
type Wrapped<T> = { value: T };
const wrappedValue: Wrapped<number> = { value: 10 };
class A<T> {
constructor(private a: T) {}
public toString(): string {
return a + ''; //
}
}
type Wrapper<S> = { value: S };
const a: Wrapper<A<number>> = { value: new A(10) };
console.log(a);
클래스 명과 동적 타입이 같으면 작동이 안된다.
기본
class NamedValue<T = string> {
private _value: T | undefined;
constructor(private name: string) {}
public setValue(value: T) {
this._value = value;
}
public getValue(): T | undefined {
return this._value;
}
public toString(): string {
return `${this.name}: ${this._value}`;
}
}
let a = new NamedValue('myNumber');
a.setValue('myValue');
console.log(a.toString());
TS 유틸리티 유형
partial 객체의 모든 속성을 선택 사항으로 변경한다.
interface Point {
x: number;
y: number;
}
let pointPart: Partial<Point> = {}; // `Partial` allows x and y to be optional
pointPart.x = 10;
인터페이스는 객체 타입을 만든다.
interface Point{
x: number;
y:number;
}
let a:Point={};
a.x = 10; // 얘네가 뒤늦게 따르게 하기 위해서
a.y = 20; // 얘네가 뒤늦게 따르게 하기 위해서
밑에와 같이 작성해야한다.
interface Point{
x: number;
y:number;
}
let a:Partial<Point>={};
a.x = 10;
a.y = 20;
필수
객체의 모든 속성을 변경한다.
interface Car {
make: string;
model: string;
mileage?: number;
}
let myCar: Required<Car> = {
make: 'Ford',
model: 'Focus',
mileage: 12000
};
mileage?: number;
물음표(?)는 선택적(optional) 속성을 의미
즉, mileage 속성은 있어도 되고, 없어도 되는 속성
Required<Car> → 모든 속성이 필수
즉, ?는 "이 속성이 없어도 괜찮다"는 뜻이고, Required<T>를 사용하면 선택적 속성이 강제로 필수가 된다.
기록
특정 키 유형과 값 유형으로 개체 유형을 단축한다.
const a: Record<string, number> = {
'Alice': 21,
'Bob': 25
};
생략
객체 유형에서 키를 제거한다.
interface Person {
name:string;
age:number;
location?: string;
}
// type을 person으로 제한
const bob :Omit<Person, 'age' | ' location'>= {
name:'Bon' ,
// age:20
}
선택
interface Person {
name:string;
age:number;
location?: string;
}
// type을 person으로 제한
const bob :Pick<Person, 'name' >= {
name:'Bon' ,
// age:20
}
리턴 타입
함수 유형의 반환 유형을 축
type PointGenerator = () => {x:number, y:number};
// Return 타입을 따르고 싶을 때 ReurnType으로 작성하기
const a :ReturnType <PointGenerator>={
x:10, y: 20
}
파라미터
type PointPrinter = (p: { x: number; y: number; }) => void;
const point: Parameters<PointPrinter>[0] = {
x: 10,
y: 20
};
void는 왜 작성한걸까? 🤔
void는 함수의 반환값이 없다는 것을 의미
이 함수는 어떤 값을 return하지 않는다는 것을 의미
생략해도 되지만, 명시적으로 적는것이 좋음
TS keyOf
interface Person {
name: string;
age: number;
}
function printPersonProperty(person: Person, property: keyof Person) {
console.log(`Printing person property ${property}: "${person[property]}"`);
}
let person = {
name: "ysh",
age: 27
};
Person의 key는 name과 age이다.
type StringMap={[key:string]:unknown};
function a(property:keyof StringMap, value:string):StringMap{
return {[property]:value};
}
// function a 를 호출할때 어떤 값을 줄 수 있을까?
console.log(a("a", "b"));
//a 함수는 첫 번째 인자로 어떤 문자열이든 받을 수 있다. 즉, a("아무 문자열", "value") 형식으로 호출하면 정상적으로 동작한다.
null의 타입이 뭔데?
let value:string|undefined|null=null;
console.log(typeof value); // object
value="hello";
console.log(typeof value); // string
value=undefined;
console.log(typeof value); // undefined
typescript는 유형에 명시적으로 추가 strictNullChecks 하지 않는 한 값을 설정해야한다.
optional chaining
interface House{
sqft:number;
yard?:{
sqft:number;
};
}
function a(house:House) {
const yardSize = house.yard?.sqft;
if(yardSize==undefined) {
console.log('No yard');
} else {
console.log(`yard is ${yardSize} sqft`);
}
}
let home:House={
sqft:500
};
a(home);
무효화 합체
function a(b:number) {
console.log(`b:${(b??'Not Available')}`);
}
a(null);
a(0);
💭 다들 실력자다..
💭 열심히 따라가자!
'💡 URECA' 카테고리의 다른 글
[URECA] DAY 10 | 자바(2) (1) | 2025.02.07 |
---|---|
[URECA] Day09 | 자바(1) (5) | 2025.02.06 |
[Day 07] JS(4), TS(1) (1) | 2025.02.04 |
[URECA] DAY 6 | JavaScript(3) (1) | 2025.02.03 |
[URECA] DAY 5 | JavaScript(2) (0) | 2025.01.24 |