// ex)
let a = 5
a = 10
//변수 a 타입은 number
// error
// a = "text"
// ex)
let text:string = "안녕"
//변수 text 타입은 string
function getStudentDetails(studentId:numeber):object{
return {null}
}
// 매개변수에 타입지정
// 반환되는 return에 타입도 명시할 수 있음 매개면수 옆에 :타입명
function getStudentDetails(studentId:numeber):void{
}
// 반환되는 return값이 없는 경우 :viod 로 명시해준다.
// void와 any가 아닌 경우에는 반드시 return 값이 존재해야된다.
// 객체 타입을 반환한다
function getStudentDetails(studentId:numeber):object{
return {null}
}
//반환되는 객체를 좀 더 자세히 명시할 수 있다.
function getStudentDetails(studentId:numeber):{
id:number,
name:string,
age:number,
checked: boolean
}{
return {null}
}
interface는 위와 같은 문제를 해결해준다.
인터페이스 선언
interface Profile{
id:number,
name:string,
age:number,
checked: boolean
}
함수의 리턴 값에 인터페이스 적용하기
function getStudentDetails(studentId:numeber):Profile{
return {null}
}
//getStudentDetails 함수의 반환값은 반드시 Profile에 정의된 프로퍼티를 모두 받아야된다
// 프로퍼티가 null이여도 상관 없는 값은 프로퍼티 옆에? 를 붙여준다.
interface Profile{
id:number,
name:string,
age?:number,
checked: boolean
}
함수의 매개변수에 인터페이스 적용하기
function saveStudentDetails(studentId:Profile):void{
}
// 1. 매개변수에 직접 값 넣기
saveStudentDetails({
id:1,
name:"김김김",
age:23,
checked: true
})
// 2. 변수에 할당하고 변수를 넣기
let student = {
id:1,
name:"김김김",
age:23,
checked: true
}
saveStudentDetails(student)
함수를 인터페이스에서 정의하기
interface Profile{
id:number,
name:string,
age?:number,
checked: boolean
// 두가지 방법으로 표현 가능
addComment: (comment:string): string,
addComment: (comment:string) => string
// comment라는 매개변수를 갖고 있으며 type은 string이다. 반환되는 값의 type은 string이다.
}
Readonly 프로퍼티
interface Profile{
readonly id:number,
name:string,
age?:number,
checked: boolean
addComment: (comment:string): string,
addComment: (comment:string) => string
}
function saveStudentDetails(studentId:Profile):void{
// error 읽기전용임
studentId.id = 3
}
saveStudentDetails({
id:1,
name:"김김김",
age:23,
checked: true
})
열거형(Enum)
// enum을 통해 선언하고 {} 내부에 선택지로 사용할 값들을 넣어준다.
enum GenderType{
Mail,
Femail
}
interface Profile{
readonly id:number,
name:string,
age?:number,
// enum으로 선언한 GenderType을 type으로 넣어준다.
gender:GenderType
checked: boolean
}
function saveStudentDetails(studentId:Profile):void{
}
saveStudentDetails({
id:1,
name:"김김김",
age:23,
// gender프로퍼티의 value는 enum으로 선언한 GenderType의 값들만 사용할 수 있음
gender:GenderType.Mail,
checked: true
})
숫자형 enum과 문자형 enum
// enum을 통해 선언하고 {} 내부에 선택지로 사용할 값들을 넣어준다.
enum GenderType{
Mail,
Femail
}
// 컴파일시 숫자로 구분되어 코드가 나타난다.
GenderType[Mail] = 0
GenderType[Femail] = 1
//문자형 enum
enum GenderType{
Mail = "mail",
Femail = "femail"
}
GenderType[Mail] = "mail"
GenderType[Femail] = "femail"
리터럴 타입
// enum을 통해 선언하고 {} 내부에 선택지로 사용할 값들을 넣어준다.
interface Profile{
readonly id:number,
name:string,
age?:number,
// 리터럴 타입은 파이프라인(|)으로 구분해준다.
gender:"mail" | "femail",
checked: boolean
}
function saveStudentDetails(studentId:Profile):void{
}
saveStudentDetails({
id:1,
name:"김김김",
age:23,
//mail과 femail이외의 문자를 입력시 에러가 나타난다.
gender: "mail",
checked: true
})
Any type
let someValue:any
Union type
// 리터럴 타입과 동일하게 |(파이프라인) 으로 구분한다.
let someValue:number | string
somValue = 5
somValue = "안녕"
//error
somValue = false
Type Aliases
// 반복되는 number | string 코드
let someValue:number | string
function someText(num:number | string):number | string{
return null
}
function someText(num:number | string):void{
}
// Type Aliases
// type키워드를 사용하여 타입을 선언 할 수 있다.
type SrtOrNum = number | string
let someValue:SrtOrNum
function someText(num:SrtOrNum):SrtOrNum{
return null
}
function someText(num:SrtOrNum):void{
}
타입가드
type SrtOrNum = number | string
let first:number
function anyNum(aanum:SrtOrNum){
// first 부분에 에러표시가 나온다.
// aanum의 타입이 string인 경우 first에 할당될 수 없기때문에
return first = aanum
}
anyNum(50)
// Typeof Operator Typeof연산자와 조건문을 같이 사용
// 변수의 데이터 타입을 반환 하는 연산자이다.
type SrtOrNum = number | string
let first:number
function anyNum(aanum:SrtOrNum){
// aanum의 타입이 string일 경우
// typeof연산자를 사용해 코드를 한번 더 검증하면 에러가 발생하지 않는다.
if(typeof aanum === string){
return first = 0
}else{
return first = aanum
}
}
anyNum(50)
// Typeof말고도 다양한 타입가드 방법이 있다.
// typescript type guards라고 검색하면 나온다.
https://www.youtube.com/watch?v=lmjQh2LrH94&list=PLJf6aFJoJtbUXW6T4lPUk7C66yEneX7MN&index=7
챕터 7까지 들음
8부터 들으면됨
// 매개변수 ()뒤에 : 로 명시해준다.
// console.log 처럼 return값이 없는 경우 :void
function sendMsg (user, msg):void {
console.log(${user},${msg})
}
sendMsg("아무개", "안녕하세야")
// return값이 string인경우
function sendMsg (user, msg):striong {
return `${user} ${meg}`
}
sendMsg("아무개", "안녕하세야")
// return 값이 배열이고 요소들이 string인 경우
function sendMsg (user, msg):sting[] {
return [user, msg]
}
sendMsg("아무개", "안녕하세야")
// 매개변수 옆에 : 로 타입을 명시해준다.
function sendMsg (user:string, msg:string):void {
console.log(${user},${msg})
}
sendMsg("아무개", "안녕하세야")
// error, msg:string msg는 스트링 값만 받을 수 있다.
sendMsg("아무개", 1)
// 선택적 매개변수를 적용하기
// msg매개변수 옆에 ? 를 붙여주면 됨
function sendMsg (user:string, msg?:string):void {
console.log(${user},${msg})
}
sendMsg("아무개")
// 앞선 interface에서 선택적 프로퍼티와 동일한 방법
-------------------------------------------------------------------------------
// 변수가 여러개이고 선택적 매개변수가 있는 경우
// 반드시 필수 매개변수 뒤에 선택적 매개변수를 넣어주어야 한다.
// 중간에 선택적 매개변수가 있는 경우 뒤에 모든 매개변수는 선택적 매개변수가 된다.
function sendMsg (id:string, user:string, age?:number, msg:string):void {
console.log(${user},${msg})
}
function sendMsg (user:string, msg?:string):void {
console.log(`${user}, ${msg}`)
}
// 아무런 값이 전달되지 않을때 undefined가 출력된다.
sendMsg("아무개")
// 아무개, undefined
// 매개변수의 default값 적용
// 매개변수 뒤에 =defaultValue 형식으로 넣어주면 된다
// msg:sting="안녕하세요!" 에서 ts의 타입추론으로 :sting를 생략시켜줘도 된다.
function sendMsg (user:string, msg="안녕하세요!"):void {
console.log(`${user}, ${msg}`)
}
sendMsg("아무개")
-------------------------------------------------------------------------------------
// 화살표함수
const sendMsg = (user:string, msg="안녕하세요!"):void => console.log(`${user}, ${msg}`)
sendMsg("아무개")
// 1:아무개, 안녕하세요!
object는 Class를 통해 생성이 가능하고, Class는 객체를 만들어 내기 위한 정보, 틀이다.
class Person{
name:string,
age:number,
job:string,
//class의 프로퍼티에 접근은 this.프로퍼티 형식으로 할 수 있다.
printPerson = ()=>{
console.log(`이름은 ${this.name}이고 나이는 ${this.age}세, 직업은 ${this.job}이다.`)
}
}
// class를 사용해 객체 생성은 new 키워드를 통해 생성이 가능하다 (생성자 함수)
// const 객체명 = new class명()
const person1 = new Person()
person1.printPerson()
// 이름은 undefined이고 나이는 NaN세, 직업은 undefined이다.
// 객체를 생성하고 프로퍼티의 값이 할당되어지지 않았기 때문.
----------------------------------------------------------------------
const person1 = new Person()
person1.name = "멋쟁이"
person1.age = 23
person1.job = "개발자"
// 함수를 호출하기 전, 프로퍼티의 값을 할당해준다.
person1.printPerson()
// 이름은 멋쟁이이고 나이는 23세, 직업은 개발자이다.
class Person{
name:string,
age:number,
job:string,
printPerson = ()=>{
console.log(`이름은 ${this.name}이고 나이는 ${this.age}세, 직업은 ${this.job}이다.`)
}
}
const person1 = new Person()
person1.name = "멋쟁이"
person1.age = 23
person1.job = "개발자"
person1.printPerson()
// 이름은 멋쟁이이고 나이는 23세, 직업은 개발자이다.
// 위의 코드를 constructor를 사용하면
class Person{
name:string,
age:number,
job:string,
constructor(name:string, age:number, job:string){
this.name = name;
this.age = age;
this.job = job
}
printPerson = ()=>{
console.log(`이름은 ${this.name}이고 나이는 ${this.age}세, 직업은 ${this.job}이다.`)}}
const person1 = new Person("멋쟁이", 23, "개발자")
person1.printPerson()
// 이름은 멋쟁이이고 나이는 23세, 직업은 개발자이다.
//아래와 같이 위의 코드에서 선언부분을 초기화 및 할당 부분에서 모두 정의할 수 있다.
class Person{
constructor(public name:string, public age:number, public job:string){
this.name = name;
this.age = age;
this.job = job
}
printPerson = ()=>{
console.log(`이름은 ${this.name}이고 나이는 ${this.age}세, 직업은 ${this.job}이다.`)}}
class를 사용해 객체를 생성할때 new class명() 의 매개변수는 constructo의 매개변수로 전달된다
constructor의 매개변수를 선택적 매개변수로 하고싶을땐 ? 를 사용해 가능하다.
접근제한자
public, private, protected
default값은 public임.
public
class 외부에서 접근 가능
class Person{
private _name:string,
age:number,
job:string,
constructor(name:string, age:number, job:string){
this.name = name;
this.age = age;
this.job = job
}
printPerson = ()=>{
console.log(`이름은 ${this.name}이고 나이는 ${this.age}세, 직업은 ${this.job}이다.`)}}
const person1 = new Person("멋쟁이", 23, "개발자")
person1.printPerson()
//error
person1.name = "바보"
//error
console.log(person1.name)
private된 값은 재선언은 물론 읽기 쓰기 조차 제한이 된다.
비공개 프로퍼티는 암묵적으로 프로퍼티 앞에 _를 붙여준다.
getter과 setter을 사용해 읽기 쓰기(재할당)를 할 수 있다.
class Person{
private _name:string,
age:number,
job:string,
constructor(name:string, age:number, job:string){
this.name = name;
this.age = age;
this.job = job
}
printPerson = ()=>{
console.log(`이름은 ${this.name}이고 나이는 ${this.age}세, 직업은 ${this.job}이다.`)}}
const person1 = new Person("멋쟁이", 23, "개발자")
person1.printPerson()
get name(){
return this._name;
}
set name(value: string){
return this._name = value;
}
// person 객체의 _name을 부를게 아니라
// get 객체의 name에 접근하는것 이다.
console.log(person1.name)
// set name에 접근 매개변수에 값을 통해 재할당 가능
person1.name("아무개")
class Person{
//객체가 생성될때 컨스트럭터의 매개변수로 전달된 값은 객체의 프로퍼티로 자동으로 할당됨
constructor(
private _name:string,
private age:number,
public job:string){
}
printPerson = ()=>{
console.log(`이름은 ${this.name}이고 나이는 ${this.age}세, 직업은 ${this.job}이다.`)}}
const person1 = new Person("멋쟁이", 23, "개발자")
/*
person.name - 멋쟁이
person.age - 23
person.job - 개발자
*/
static
정적 매서드, 속성
static createEmployee(name: string) {
return
}
static 키워드를 사용해주고 {}객체를 리턴해준다.
const employee1 = Department.createEmployee("sandy");
호출은 위와 같이 new 키워드를 사용하지 않고 바로 class명.static요소명 으로 가능하다.
프로퍼티는 static name = "bob" 같이 정의가 가능
** static프로퍼티는 constructor에서 this.static프로퍼티명 으로 접근시 에러를 호출한다.
class명.static프로퍼티명 으로 접근이 가능하ㅏㄷ.
abstract
추상 클래스
abstract class Department {
abstract describe(this: Department): void;
}
클래스 내부 abstract키워드로 되어있는 매서드가 있는 경우
클래스에서 abstract를 붙여준다.
Department클래스를 상속 받아 생성된 클래스는 반드시
describe() 함수가 포함되어야되며 내부 로직은 :void로 return이 되지 않는 함수로 자유롭게 코드를 작성할 수 있다.
싱글패턴
클래스를 활용해 매번 다른 생성자 함수를 통해 다른 객체를 만들때가 아닌 일정한 값을 가진 객체를 호출하기 위해
private static instance: ITDepartment;
instance라는 속성을 private static키워드를 사용해 생성해주고 type은 정의하는 class로 해준다.
private constructor constructor앞에 private키워드를 사용해주고
static getinstance() {
if (ITDepartment.instance) {
return this.instance;
}
this.instance = new ITDepartment("d1", "kokoa", ["jone", "kate", "bob"]);
return this.instance;
}
위의 로직을 추가해주고
const it = ITDepartment.getinstance();
const i2t = ITDepartment.getinstance();
위와같이 함수를 호출해 객체를 생성하게되면 둘 다 모두 같은 값을 출력하게된다.
interface와 type의 차이
둘다 모두 type을 지정해주는건 맞지만 interface는 객체의 타입으로 한정되어 있고 type alias는 모든(any) 타입에 이름을 달아줄 수 있다.
확장을 하는 방법은 다를지언정 type과 interface 둘 다 확장이 가능한 것을 볼 수 있다.
여기서 차이점이 발생하는데, 인터페이스의 경우에는 선언적 확장이 가능하다는 점이다.
type PositionType = {
x: number;
y: number;
};
interface PositionInterface {
x: number;
y: number;
}
// Extends
interface ZpositionInterface extends PositionInterface {
z: number;
}
type ZpositionType = PositionType & { z: number };
// only interfaces can be merged.
interface PositionInterface {
z: number;
}
선언적 확장은 동일한 이름으로 interface를 선언해줬을 경우 자동적으로 하나로 합쳐진다.
이는 type에서는 불가능한 기능이므로 interface만 가능하다.
그리고 확장 기능에 있어서 성능적으로 interface 좀 더 준수한 성능을 가지고 있다고 한다.
type은 경우 그저 interface처럼 구현을 한다기보다는 값을 담아두기 위해 사용하고, interface는 하나의 규격이기 때문에 그것을 이용해 구현하고자 할 때 사용하면 될 거라 생각한다.
결론은 인터페이스는 객체의 값을 구조화하여 정의할때 사용 하도록 스스로 약속
interface PersonalInfo {
name: string;
age: number;
job: string[];
someText(text: number): void;
}
class Person implements PersonalInfo {
name: string;
age: number;
job: string[];
constructor(name: string, age: number, job: string[]) {
this.name = name;
this.age = age;
this.job = job;
}
someText(text: number) {
console.log(text);
}
}
interface와 implements를 활용해 class를 생성할때 특정한 객체 값을 내포할 수 있도록 정의가 가능하다.
interface PersonalInfo {
readonly name: string;
age: number;
job: string[];
someText(text: number): void;
}
interface PersonalDetailInfo {
a: string;
}
class Person implements PersonalInfo, PersonalDetailInfo
, 로 구분해 여러개의 interface를 갖도록 할 수 있다.
interface PersonalInfo {
readonly name: string;
age: number;
job: string[];
someText(text: number): void;
}
interface PersonalDetailInfo extends PersonalInfo {
a?: string;
}
class Person implements PersonalDetailInfo
extends를 사용해 중첩도 가능 / class는 extends를 하나만 활용할 수 있지만 interface에서는 ,를 사용해 중첩이 가능하다 !
인터페이스로 함수 타입 정의 !
인터페이스는 객체의 형태를 구조화 하기 위해 !!
함수도 객체에 포함되는걸 잊지말자.
함수또한 객체이므로 인터페이스로 함수의 형태를 구조화할 수 있다.
type addFu = (n1: number, n2: number) => number;
이 구문을
interface addFu {
(n1: number, n2: number): number;
}
위와 같이 변경해줄 수 있다.
const addfunc: addFu = (n1: number, n2: number) => {
const total = n1 + n2;
return total;
};