type UserA = {
name: string
age: number
}
interface UserB {
name: string
age: number
isValid?: boolean
readonly val: string
}
const user: UserB{
name: 'kim',
age: 85
}
user.val = 5 // 에러
흠! 여러 타입을 선언한것과 뭐가 다를까?
찾아보니 interface
는 선언 병합이 가능하다고 한다. 같은이름을 선언하면 컴파일 시점에 둘이 합쳐짐.
그래서 interface
를 조금 더 권장한다고한다.
?
키워드 : 해당 프로퍼티가 있어도 없어도 됨readonly
키워드 : 해당 프로퍼티 재할당 불가.interface User{
name:string
age?:number
}
interface GetUserNameI{
(u: User): string
}
u
(순서만 상관있음 이름중요 x)의 타입을 User
로 지정string
으로 지정이렇게 interface
로 함수의 타입을 지정해줄 수 있다. 이를 호출 시그니처라고한다.
interface UserI{
name: string
getName():string //메소드 타입 지정
}
class User implements UserI {
public name
constructor(name:string){
this.name = name;
}
getName(){
return this.name
}
}
const user = new User('kim');
user.getName() // kim
function hello(userClass, msg:string){
const user = new userClass('kim');
return `Hello ${user.getName()}, ${msg}`
}
hello(User, 'good morning!');
완전 자바잖아...? 😮
클래스는 타입을 요래요래 지정하면 된다
interface UserC {
new (n: string): UserI // new로 생성한 생성자함수(클래스)는 UserI를 반환한다.
}
이를 생성(contructor) 시그니처라고 한다
튜플이나 배열을 뜻하는 거겠지?
interface ArrLike {
[key: number]: string
}
const arrLike: ArrLike = {0:"A", 1:"B"};
arrLike[1] // B
//가변적인 인덱싱타입은 이렇게 사용한다
interface User{
//키에 문자, 값에 문자,숫자가 들어올수 있다
[key: string]: number | string
//name, age가 문자와 숫자로 무조건 존재해야한다
name: string
age: number
}
const user:User = {
name:"kim",
age:85,
email:...
city:"서울",
value: 2222,
isValid:true //존재할수 없는 타입이라 에러
}
function getValues(payload: //unknown이면 에러가 난다. Payload){
if(payload && payload.constructor === Object){
return Object.keys(payload).map(key => payload[key]) // 이러면 오류가난다...
}
}
//payload에 들어갈 타입을 지정해주어야한다...!
interface Payload {
[key: string]: unknown;
}
인터페이스의 각 타입을 하나씩만 활용할수도 있다.
interface Test {
name: string
age: number
}
const a: User['name'] = "kim" // kim
클래스처럼 extends
키워드를 사용한다
interface UserA{
name: string
age: number
}
interface UserB extends UserA{
isValid: boolean
}
const user: UserB = {
name: "kim",
age: 8,
isValid: true
}
TS에서도 당연히 this
를 쓸텐데, 명시적 this
가 뭘까? 일반함수에서는 필요없을텐데 말이다.
interface User{
name:string
}
function greet(msg:string){
return `Hello${this.name}, ${msg}` //이렇게 사용하면 this가 전역객체기에 오류가난다
}
//수정후
function greet(this: User, msg:string){
return `Hello${this.name}, ${msg}`
}
음...JS와 용법이 달라서 헷갈린다. 많이 써보는 게 최고겠지?
function addString(x: string, y:string): string{
return x+y
}
function addString(x: number, y:number): number{
return x+y
}
function addString(x: string, y:string): string
function addString(x: number, y:number): number
function any(x:any, y:any): any{
return x+y
}
선언부를 위처럼 여러개 작성한다. 신기하구먼
interface
에서도 함수 오버로딩이 가능하다
interface UserBase{
name:string
age:number
}
interface User extends UserBase{
updateInfo(newUser: UserBase): User
updateInfo(name: string, age: number): User
}
const user: User = {
name: 'kim',
age: 85,
updateInfo: function(nameOrUser: UserBase | string, age?:number){
if(typeof nameOrUser === 'string' && age !+= undefined){
this.name = nameOrUser;
this.age = age;
} else if (typeof nameOrUser === 'object'){
this.name = nameOrUser.name;
this.age = nameOrUser.age
}
return this;
}
}
자바처럼 public, private, protect, static, readonly
가 있음.
이 접근제어자들은 모두 TS에서만 작동함.
=> 예를들어 js에서도 private하게 작동하고싶다면 #
키워드 사용해서 private하게 만들어야함!
interface UserA {
name: string,
age: number,
val: number
}
class User implement UserA {
private readonly name //setter로 재정의 금지.
protected age // getter, setter를 따로 적어주어야 한다.
val // public은 디폴트여서 작성하지 않아도 됨
constructor(name: string, age: number, val: number){
this.name = name;
this.age = age;
this.val = val;
}
}
//아래와 같이 중복되는 부분을 제거해줄수 있다.
class User implement UserA {
constructor(
private readonly name: string,
protected age: number,
val: number){}
}
private | protected | public | |
---|---|---|---|
클래스내부 호출 | o | o | o |
자식클래스에서 호출 | x | ㅇ | o |
클래스 외부에서 호출 | x | x | o |
이런차이가 있고 static
은 클래스 자체의 멤버(인스턴스화 되면 없어짐)가 되는것이다. private
와 헷갈릴 수 있지만, static
은
클래스 외부에서 호출 가능함
readonly
는 contructor
내부에서 초기화 한 뒤 재할당 불가능이다.
abstract class Animal{
abstract name: string,
abstract age: number,
getName(){
console.log(this.name);
}
abstract getAge(): number;
}
class Dog extends Animal{
constructor(public color: string){
super(name, age)
}
//추상클래스 내부 abstract로 선언된 메서드는 무조건 구현해주어야함.
getAge(){
return this.age
}
}
const maltese = new Dog("rei", "11", "white")
언뜻보면 interface
와 유사하다. 둘의 차이는 뭘까?
extends
키워드로 상속받고 super
키워드로 슈퍼클래스의 constructor
를 호출해야함.interface
는 클래스가 아니다. implement
키워드로 구현해야할 멤버들을 받아 구현하면됨.interface
의 구현부는 없다.interface
는 여러개를 implement
로 받아올수 있음.요 차이다.